ClientCodeTranslatorSnippetBasedTests.swift 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  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. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  42. public protocol NamespaceA_ServiceAClientProtocol: Sendable {
  43. /// Documentation for MethodA
  44. func methodA<R>(
  45. request: ClientRequest.Single<NamespaceA_ServiceARequest>,
  46. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  47. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  48. options: CallOptions,
  49. _ body: @Sendable @escaping (ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> R
  50. ) async throws -> R where R: Sendable
  51. }
  52. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  53. extension NamespaceA_ServiceA.ClientProtocol {
  54. public func methodA<R>(
  55. request: ClientRequest.Single<NamespaceA_ServiceARequest>,
  56. options: CallOptions = .defaults,
  57. _ body: @Sendable @escaping (ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> R = {
  58. try $0.message
  59. }
  60. ) async throws -> R where R: Sendable {
  61. try await self.methodA(
  62. request: request,
  63. serializer: ProtobufSerializer<NamespaceA_ServiceARequest>(),
  64. deserializer: ProtobufDeserializer<NamespaceA_ServiceAResponse>(),
  65. options: options,
  66. body
  67. )
  68. }
  69. }
  70. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  71. extension NamespaceA_ServiceA.ClientProtocol {
  72. /// Documentation for MethodA
  73. public func methodA<Result>(
  74. _ message: NamespaceA_ServiceARequest,
  75. metadata: GRPCCore.Metadata = [:],
  76. options: GRPCCore.CallOptions = .defaults,
  77. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> Result = {
  78. try $0.message
  79. }
  80. ) async throws -> Result where Result: Sendable {
  81. let request = GRPCCore.ClientRequest.Single<NamespaceA_ServiceARequest>(
  82. message: message,
  83. metadata: metadata
  84. )
  85. return try await self.methodA(
  86. request: request,
  87. options: options,
  88. handleResponse
  89. )
  90. }
  91. }
  92. /// Documentation for ServiceA
  93. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  94. public struct NamespaceA_ServiceAClient: NamespaceA_ServiceA.ClientProtocol {
  95. private let client: GRPCCore.GRPCClient
  96. public init(wrapping client: GRPCCore.GRPCClient) {
  97. self.client = client
  98. }
  99. /// Documentation for MethodA
  100. public func methodA<R>(
  101. request: ClientRequest.Single<NamespaceA_ServiceARequest>,
  102. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  103. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  104. options: CallOptions = .defaults,
  105. _ body: @Sendable @escaping (ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> R = {
  106. try $0.message
  107. }
  108. ) async throws -> R where R: Sendable {
  109. try await self.client.unary(
  110. request: request,
  111. descriptor: NamespaceA_ServiceA.Method.MethodA.descriptor,
  112. serializer: serializer,
  113. deserializer: deserializer,
  114. options: options,
  115. handler: body
  116. )
  117. }
  118. }
  119. """
  120. try self.assertClientCodeTranslation(
  121. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  122. expectedSwift: expectedSwift,
  123. accessLevel: .public
  124. )
  125. }
  126. func testClientCodeTranslatorClientStreamingMethod() throws {
  127. let method = MethodDescriptor(
  128. documentation: "/// Documentation for MethodA",
  129. name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
  130. isInputStreaming: true,
  131. isOutputStreaming: false,
  132. inputType: "NamespaceA_ServiceARequest",
  133. outputType: "NamespaceA_ServiceAResponse"
  134. )
  135. let service = ServiceDescriptor(
  136. documentation: "/// Documentation for ServiceA",
  137. name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
  138. namespace: Name(base: "namespaceA", generatedUpperCase: "NamespaceA", generatedLowerCase: ""),
  139. methods: [method]
  140. )
  141. let expectedSwift =
  142. """
  143. /// Documentation for ServiceA
  144. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  145. public protocol NamespaceA_ServiceAClientProtocol: Sendable {
  146. /// Documentation for MethodA
  147. func methodA<R>(
  148. request: ClientRequest.Stream<NamespaceA_ServiceARequest>,
  149. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  150. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  151. options: CallOptions,
  152. _ body: @Sendable @escaping (ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> R
  153. ) async throws -> R where R: Sendable
  154. }
  155. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  156. extension NamespaceA_ServiceA.ClientProtocol {
  157. public func methodA<R>(
  158. request: ClientRequest.Stream<NamespaceA_ServiceARequest>,
  159. options: CallOptions = .defaults,
  160. _ body: @Sendable @escaping (ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> R = {
  161. try $0.message
  162. }
  163. ) async throws -> R where R: Sendable {
  164. try await self.methodA(
  165. request: request,
  166. serializer: ProtobufSerializer<NamespaceA_ServiceARequest>(),
  167. deserializer: ProtobufDeserializer<NamespaceA_ServiceAResponse>(),
  168. options: options,
  169. body
  170. )
  171. }
  172. }
  173. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  174. extension NamespaceA_ServiceA.ClientProtocol {
  175. /// Documentation for MethodA
  176. public func methodA<Result>(
  177. metadata: GRPCCore.Metadata = [:],
  178. options: GRPCCore.CallOptions = .defaults,
  179. requestProducer: @Sendable @escaping (GRPCCore.RPCWriter<NamespaceA_ServiceARequest>) async throws -> Void,
  180. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> Result = {
  181. try $0.message
  182. }
  183. ) async throws -> Result where Result: Sendable {
  184. let request = GRPCCore.ClientRequest.Stream<NamespaceA_ServiceARequest>(
  185. metadata: metadata,
  186. producer: requestProducer
  187. )
  188. return try await self.methodA(
  189. request: request,
  190. options: options,
  191. handleResponse
  192. )
  193. }
  194. }
  195. /// Documentation for ServiceA
  196. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  197. public struct NamespaceA_ServiceAClient: NamespaceA_ServiceA.ClientProtocol {
  198. private let client: GRPCCore.GRPCClient
  199. public init(wrapping client: GRPCCore.GRPCClient) {
  200. self.client = client
  201. }
  202. /// Documentation for MethodA
  203. public func methodA<R>(
  204. request: ClientRequest.Stream<NamespaceA_ServiceARequest>,
  205. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  206. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  207. options: CallOptions = .defaults,
  208. _ body: @Sendable @escaping (ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> R = {
  209. try $0.message
  210. }
  211. ) async throws -> R where R: Sendable {
  212. try await self.client.clientStreaming(
  213. request: request,
  214. descriptor: NamespaceA_ServiceA.Method.MethodA.descriptor,
  215. serializer: serializer,
  216. deserializer: deserializer,
  217. options: options,
  218. handler: body
  219. )
  220. }
  221. }
  222. """
  223. try self.assertClientCodeTranslation(
  224. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  225. expectedSwift: expectedSwift,
  226. accessLevel: .public
  227. )
  228. }
  229. func testClientCodeTranslatorServerStreamingMethod() throws {
  230. let method = MethodDescriptor(
  231. documentation: "/// Documentation for MethodA",
  232. name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
  233. isInputStreaming: false,
  234. isOutputStreaming: true,
  235. inputType: "NamespaceA_ServiceARequest",
  236. outputType: "NamespaceA_ServiceAResponse"
  237. )
  238. let service = ServiceDescriptor(
  239. documentation: "/// Documentation for ServiceA",
  240. name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
  241. namespace: Name(base: "namespaceA", generatedUpperCase: "NamespaceA", generatedLowerCase: ""),
  242. methods: [method]
  243. )
  244. let expectedSwift =
  245. """
  246. /// Documentation for ServiceA
  247. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  248. public protocol NamespaceA_ServiceAClientProtocol: Sendable {
  249. /// Documentation for MethodA
  250. func methodA<R>(
  251. request: ClientRequest.Single<NamespaceA_ServiceARequest>,
  252. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  253. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  254. options: CallOptions,
  255. _ body: @Sendable @escaping (ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> R
  256. ) async throws -> R where R: Sendable
  257. }
  258. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  259. extension NamespaceA_ServiceA.ClientProtocol {
  260. public func methodA<R>(
  261. request: ClientRequest.Single<NamespaceA_ServiceARequest>,
  262. options: CallOptions = .defaults,
  263. _ body: @Sendable @escaping (ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> R
  264. ) async throws -> R where R: Sendable {
  265. try await self.methodA(
  266. request: request,
  267. serializer: ProtobufSerializer<NamespaceA_ServiceARequest>(),
  268. deserializer: ProtobufDeserializer<NamespaceA_ServiceAResponse>(),
  269. options: options,
  270. body
  271. )
  272. }
  273. }
  274. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  275. extension NamespaceA_ServiceA.ClientProtocol {
  276. /// Documentation for MethodA
  277. public func methodA<Result>(
  278. _ message: NamespaceA_ServiceARequest,
  279. metadata: GRPCCore.Metadata = [:],
  280. options: GRPCCore.CallOptions = .defaults,
  281. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> Result
  282. ) async throws -> Result where Result: Sendable {
  283. let request = GRPCCore.ClientRequest.Single<NamespaceA_ServiceARequest>(
  284. message: message,
  285. metadata: metadata
  286. )
  287. return try await self.methodA(
  288. request: request,
  289. options: options,
  290. handleResponse
  291. )
  292. }
  293. }
  294. /// Documentation for ServiceA
  295. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  296. public struct NamespaceA_ServiceAClient: NamespaceA_ServiceA.ClientProtocol {
  297. private let client: GRPCCore.GRPCClient
  298. public init(wrapping client: GRPCCore.GRPCClient) {
  299. self.client = client
  300. }
  301. /// Documentation for MethodA
  302. public func methodA<R>(
  303. request: ClientRequest.Single<NamespaceA_ServiceARequest>,
  304. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  305. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  306. options: CallOptions = .defaults,
  307. _ body: @Sendable @escaping (ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> R
  308. ) async throws -> R where R: Sendable {
  309. try await self.client.serverStreaming(
  310. request: request,
  311. descriptor: NamespaceA_ServiceA.Method.MethodA.descriptor,
  312. serializer: serializer,
  313. deserializer: deserializer,
  314. options: options,
  315. handler: body
  316. )
  317. }
  318. }
  319. """
  320. try self.assertClientCodeTranslation(
  321. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  322. expectedSwift: expectedSwift,
  323. accessLevel: .public
  324. )
  325. }
  326. func testClientCodeTranslatorBidirectionalStreamingMethod() throws {
  327. let method = MethodDescriptor(
  328. documentation: "/// Documentation for MethodA",
  329. name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
  330. isInputStreaming: true,
  331. isOutputStreaming: true,
  332. inputType: "NamespaceA_ServiceARequest",
  333. outputType: "NamespaceA_ServiceAResponse"
  334. )
  335. let service = ServiceDescriptor(
  336. documentation: "/// Documentation for ServiceA",
  337. name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
  338. namespace: Name(base: "namespaceA", generatedUpperCase: "NamespaceA", generatedLowerCase: ""),
  339. methods: [method]
  340. )
  341. let expectedSwift =
  342. """
  343. /// Documentation for ServiceA
  344. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  345. public protocol NamespaceA_ServiceAClientProtocol: Sendable {
  346. /// Documentation for MethodA
  347. func methodA<R>(
  348. request: ClientRequest.Stream<NamespaceA_ServiceARequest>,
  349. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  350. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  351. options: CallOptions,
  352. _ body: @Sendable @escaping (ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> R
  353. ) async throws -> R where R: Sendable
  354. }
  355. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  356. extension NamespaceA_ServiceA.ClientProtocol {
  357. public func methodA<R>(
  358. request: ClientRequest.Stream<NamespaceA_ServiceARequest>,
  359. options: CallOptions = .defaults,
  360. _ body: @Sendable @escaping (ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> R
  361. ) async throws -> R where R: Sendable {
  362. try await self.methodA(
  363. request: request,
  364. serializer: ProtobufSerializer<NamespaceA_ServiceARequest>(),
  365. deserializer: ProtobufDeserializer<NamespaceA_ServiceAResponse>(),
  366. options: options,
  367. body
  368. )
  369. }
  370. }
  371. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  372. extension NamespaceA_ServiceA.ClientProtocol {
  373. /// Documentation for MethodA
  374. public func methodA<Result>(
  375. metadata: GRPCCore.Metadata = [:],
  376. options: GRPCCore.CallOptions = .defaults,
  377. requestProducer: @Sendable @escaping (GRPCCore.RPCWriter<NamespaceA_ServiceARequest>) async throws -> Void,
  378. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> Result
  379. ) async throws -> Result where Result: Sendable {
  380. let request = GRPCCore.ClientRequest.Stream<NamespaceA_ServiceARequest>(
  381. metadata: metadata,
  382. producer: requestProducer
  383. )
  384. return try await self.methodA(
  385. request: request,
  386. options: options,
  387. handleResponse
  388. )
  389. }
  390. }
  391. /// Documentation for ServiceA
  392. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  393. public struct NamespaceA_ServiceAClient: NamespaceA_ServiceA.ClientProtocol {
  394. private let client: GRPCCore.GRPCClient
  395. public init(wrapping client: GRPCCore.GRPCClient) {
  396. self.client = client
  397. }
  398. /// Documentation for MethodA
  399. public func methodA<R>(
  400. request: ClientRequest.Stream<NamespaceA_ServiceARequest>,
  401. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  402. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  403. options: CallOptions = .defaults,
  404. _ body: @Sendable @escaping (ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> R
  405. ) async throws -> R where R: Sendable {
  406. try await self.client.bidirectionalStreaming(
  407. request: request,
  408. descriptor: NamespaceA_ServiceA.Method.MethodA.descriptor,
  409. serializer: serializer,
  410. deserializer: deserializer,
  411. options: options,
  412. handler: body
  413. )
  414. }
  415. }
  416. """
  417. try self.assertClientCodeTranslation(
  418. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  419. expectedSwift: expectedSwift,
  420. accessLevel: .public
  421. )
  422. }
  423. func testClientCodeTranslatorMultipleMethod() throws {
  424. let methodA = MethodDescriptor(
  425. documentation: "/// Documentation for MethodA",
  426. name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
  427. isInputStreaming: true,
  428. isOutputStreaming: false,
  429. inputType: "NamespaceA_ServiceARequest",
  430. outputType: "NamespaceA_ServiceAResponse"
  431. )
  432. let methodB = MethodDescriptor(
  433. documentation: "/// Documentation for MethodB",
  434. name: Name(base: "MethodB", generatedUpperCase: "MethodB", generatedLowerCase: "methodB"),
  435. isInputStreaming: false,
  436. isOutputStreaming: true,
  437. inputType: "NamespaceA_ServiceARequest",
  438. outputType: "NamespaceA_ServiceAResponse"
  439. )
  440. let service = ServiceDescriptor(
  441. documentation: "/// Documentation for ServiceA",
  442. name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
  443. namespace: Name(base: "namespaceA", generatedUpperCase: "NamespaceA", generatedLowerCase: ""),
  444. methods: [methodA, methodB]
  445. )
  446. let expectedSwift =
  447. """
  448. /// Documentation for ServiceA
  449. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  450. package protocol NamespaceA_ServiceAClientProtocol: Sendable {
  451. /// Documentation for MethodA
  452. func methodA<R>(
  453. request: ClientRequest.Stream<NamespaceA_ServiceARequest>,
  454. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  455. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  456. options: CallOptions,
  457. _ body: @Sendable @escaping (ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> R
  458. ) async throws -> R where R: Sendable
  459. /// Documentation for MethodB
  460. func methodB<R>(
  461. request: ClientRequest.Single<NamespaceA_ServiceARequest>,
  462. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  463. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  464. options: CallOptions,
  465. _ body: @Sendable @escaping (ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> R
  466. ) async throws -> R where R: Sendable
  467. }
  468. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  469. extension NamespaceA_ServiceA.ClientProtocol {
  470. package func methodA<R>(
  471. request: ClientRequest.Stream<NamespaceA_ServiceARequest>,
  472. options: CallOptions = .defaults,
  473. _ body: @Sendable @escaping (ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> R = {
  474. try $0.message
  475. }
  476. ) async throws -> R where R: Sendable {
  477. try await self.methodA(
  478. request: request,
  479. serializer: ProtobufSerializer<NamespaceA_ServiceARequest>(),
  480. deserializer: ProtobufDeserializer<NamespaceA_ServiceAResponse>(),
  481. options: options,
  482. body
  483. )
  484. }
  485. package func methodB<R>(
  486. request: ClientRequest.Single<NamespaceA_ServiceARequest>,
  487. options: CallOptions = .defaults,
  488. _ body: @Sendable @escaping (ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> R
  489. ) async throws -> R where R: Sendable {
  490. try await self.methodB(
  491. request: request,
  492. serializer: ProtobufSerializer<NamespaceA_ServiceARequest>(),
  493. deserializer: ProtobufDeserializer<NamespaceA_ServiceAResponse>(),
  494. options: options,
  495. body
  496. )
  497. }
  498. }
  499. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  500. extension NamespaceA_ServiceA.ClientProtocol {
  501. /// Documentation for MethodA
  502. package func methodA<Result>(
  503. metadata: GRPCCore.Metadata = [:],
  504. options: GRPCCore.CallOptions = .defaults,
  505. requestProducer: @Sendable @escaping (GRPCCore.RPCWriter<NamespaceA_ServiceARequest>) async throws -> Void,
  506. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> Result = {
  507. try $0.message
  508. }
  509. ) async throws -> Result where Result: Sendable {
  510. let request = GRPCCore.ClientRequest.Stream<NamespaceA_ServiceARequest>(
  511. metadata: metadata,
  512. producer: requestProducer
  513. )
  514. return try await self.methodA(
  515. request: request,
  516. options: options,
  517. handleResponse
  518. )
  519. }
  520. /// Documentation for MethodB
  521. package func methodB<Result>(
  522. _ message: NamespaceA_ServiceARequest,
  523. metadata: GRPCCore.Metadata = [:],
  524. options: GRPCCore.CallOptions = .defaults,
  525. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> Result
  526. ) async throws -> Result where Result: Sendable {
  527. let request = GRPCCore.ClientRequest.Single<NamespaceA_ServiceARequest>(
  528. message: message,
  529. metadata: metadata
  530. )
  531. return try await self.methodB(
  532. request: request,
  533. options: options,
  534. handleResponse
  535. )
  536. }
  537. }
  538. /// Documentation for ServiceA
  539. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  540. package struct NamespaceA_ServiceAClient: NamespaceA_ServiceA.ClientProtocol {
  541. private let client: GRPCCore.GRPCClient
  542. package init(wrapping client: GRPCCore.GRPCClient) {
  543. self.client = client
  544. }
  545. /// Documentation for MethodA
  546. package func methodA<R>(
  547. request: ClientRequest.Stream<NamespaceA_ServiceARequest>,
  548. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  549. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  550. options: CallOptions = .defaults,
  551. _ body: @Sendable @escaping (ClientResponse.Single<NamespaceA_ServiceAResponse>) async throws -> R = {
  552. try $0.message
  553. }
  554. ) async throws -> R where R: Sendable {
  555. try await self.client.clientStreaming(
  556. request: request,
  557. descriptor: NamespaceA_ServiceA.Method.MethodA.descriptor,
  558. serializer: serializer,
  559. deserializer: deserializer,
  560. options: options,
  561. handler: body
  562. )
  563. }
  564. /// Documentation for MethodB
  565. package func methodB<R>(
  566. request: ClientRequest.Single<NamespaceA_ServiceARequest>,
  567. serializer: some MessageSerializer<NamespaceA_ServiceARequest>,
  568. deserializer: some MessageDeserializer<NamespaceA_ServiceAResponse>,
  569. options: CallOptions = .defaults,
  570. _ body: @Sendable @escaping (ClientResponse.Stream<NamespaceA_ServiceAResponse>) async throws -> R
  571. ) async throws -> R where R: Sendable {
  572. try await self.client.serverStreaming(
  573. request: request,
  574. descriptor: NamespaceA_ServiceA.Method.MethodB.descriptor,
  575. serializer: serializer,
  576. deserializer: deserializer,
  577. options: options,
  578. handler: body
  579. )
  580. }
  581. }
  582. """
  583. try self.assertClientCodeTranslation(
  584. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  585. expectedSwift: expectedSwift,
  586. accessLevel: .package
  587. )
  588. }
  589. func testClientCodeTranslatorNoNamespaceService() throws {
  590. let method = MethodDescriptor(
  591. documentation: "/// Documentation for MethodA",
  592. name: Name(base: "MethodA", generatedUpperCase: "MethodA", generatedLowerCase: "methodA"),
  593. isInputStreaming: false,
  594. isOutputStreaming: false,
  595. inputType: "ServiceARequest",
  596. outputType: "ServiceAResponse"
  597. )
  598. let service = ServiceDescriptor(
  599. documentation: "/// Documentation for ServiceA",
  600. name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
  601. namespace: Name(base: "", generatedUpperCase: "", generatedLowerCase: ""),
  602. methods: [method]
  603. )
  604. let expectedSwift =
  605. """
  606. /// Documentation for ServiceA
  607. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  608. internal protocol ServiceAClientProtocol: Sendable {
  609. /// Documentation for MethodA
  610. func methodA<R>(
  611. request: ClientRequest.Single<ServiceARequest>,
  612. serializer: some MessageSerializer<ServiceARequest>,
  613. deserializer: some MessageDeserializer<ServiceAResponse>,
  614. options: CallOptions,
  615. _ body: @Sendable @escaping (ClientResponse.Single<ServiceAResponse>) async throws -> R
  616. ) async throws -> R where R: Sendable
  617. }
  618. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  619. extension ServiceA.ClientProtocol {
  620. internal func methodA<R>(
  621. request: ClientRequest.Single<ServiceARequest>,
  622. options: CallOptions = .defaults,
  623. _ body: @Sendable @escaping (ClientResponse.Single<ServiceAResponse>) async throws -> R = {
  624. try $0.message
  625. }
  626. ) async throws -> R where R: Sendable {
  627. try await self.methodA(
  628. request: request,
  629. serializer: ProtobufSerializer<ServiceARequest>(),
  630. deserializer: ProtobufDeserializer<ServiceAResponse>(),
  631. options: options,
  632. body
  633. )
  634. }
  635. }
  636. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  637. extension ServiceA.ClientProtocol {
  638. /// Documentation for MethodA
  639. internal func methodA<Result>(
  640. _ message: ServiceARequest,
  641. metadata: GRPCCore.Metadata = [:],
  642. options: GRPCCore.CallOptions = .defaults,
  643. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single<ServiceAResponse>) async throws -> Result = {
  644. try $0.message
  645. }
  646. ) async throws -> Result where Result: Sendable {
  647. let request = GRPCCore.ClientRequest.Single<ServiceARequest>(
  648. message: message,
  649. metadata: metadata
  650. )
  651. return try await self.methodA(
  652. request: request,
  653. options: options,
  654. handleResponse
  655. )
  656. }
  657. }
  658. /// Documentation for ServiceA
  659. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  660. internal struct ServiceAClient: ServiceA.ClientProtocol {
  661. private let client: GRPCCore.GRPCClient
  662. internal init(wrapping client: GRPCCore.GRPCClient) {
  663. self.client = client
  664. }
  665. /// Documentation for MethodA
  666. internal func methodA<R>(
  667. request: ClientRequest.Single<ServiceARequest>,
  668. serializer: some MessageSerializer<ServiceARequest>,
  669. deserializer: some MessageDeserializer<ServiceAResponse>,
  670. options: CallOptions = .defaults,
  671. _ body: @Sendable @escaping (ClientResponse.Single<ServiceAResponse>) async throws -> R = {
  672. try $0.message
  673. }
  674. ) async throws -> R where R: Sendable {
  675. try await self.client.unary(
  676. request: request,
  677. descriptor: ServiceA.Method.MethodA.descriptor,
  678. serializer: serializer,
  679. deserializer: deserializer,
  680. options: options,
  681. handler: body
  682. )
  683. }
  684. }
  685. """
  686. try self.assertClientCodeTranslation(
  687. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  688. expectedSwift: expectedSwift,
  689. accessLevel: .internal
  690. )
  691. }
  692. func testClientCodeTranslatorMultipleServices() throws {
  693. let serviceA = ServiceDescriptor(
  694. documentation: "/// Documentation for ServiceA",
  695. name: Name(base: "ServiceA", generatedUpperCase: "ServiceA", generatedLowerCase: ""),
  696. namespace: Name(
  697. base: "nammespaceA",
  698. generatedUpperCase: "NamespaceA",
  699. generatedLowerCase: ""
  700. ),
  701. methods: []
  702. )
  703. let serviceB = ServiceDescriptor(
  704. documentation: """
  705. /// Documentation for ServiceB
  706. ///
  707. /// Line 2
  708. """,
  709. name: Name(base: "ServiceB", generatedUpperCase: "ServiceB", generatedLowerCase: ""),
  710. namespace: Name(base: "", generatedUpperCase: "", generatedLowerCase: ""),
  711. methods: []
  712. )
  713. let expectedSwift =
  714. """
  715. /// Documentation for ServiceA
  716. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  717. public protocol NamespaceA_ServiceAClientProtocol: Sendable {}
  718. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  719. extension NamespaceA_ServiceA.ClientProtocol {
  720. }
  721. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  722. extension NamespaceA_ServiceA.ClientProtocol {
  723. }
  724. /// Documentation for ServiceA
  725. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  726. public struct NamespaceA_ServiceAClient: NamespaceA_ServiceA.ClientProtocol {
  727. private let client: GRPCCore.GRPCClient
  728. public init(wrapping client: GRPCCore.GRPCClient) {
  729. self.client = client
  730. }
  731. }
  732. /// Documentation for ServiceB
  733. ///
  734. /// Line 2
  735. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  736. public protocol ServiceBClientProtocol: Sendable {}
  737. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  738. extension ServiceB.ClientProtocol {
  739. }
  740. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  741. extension ServiceB.ClientProtocol {
  742. }
  743. /// Documentation for ServiceB
  744. ///
  745. /// Line 2
  746. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  747. public struct ServiceBClient: ServiceB.ClientProtocol {
  748. private let client: GRPCCore.GRPCClient
  749. public init(wrapping client: GRPCCore.GRPCClient) {
  750. self.client = client
  751. }
  752. }
  753. """
  754. try self.assertClientCodeTranslation(
  755. codeGenerationRequest: makeCodeGenerationRequest(services: [serviceA, serviceB]),
  756. expectedSwift: expectedSwift,
  757. accessLevel: .public
  758. )
  759. }
  760. private func assertClientCodeTranslation(
  761. codeGenerationRequest: CodeGenerationRequest,
  762. expectedSwift: String,
  763. accessLevel: SourceGenerator.Configuration.AccessLevel,
  764. file: StaticString = #filePath,
  765. line: UInt = #line
  766. ) throws {
  767. let translator = ClientCodeTranslator(accessLevel: accessLevel)
  768. let codeBlocks = try translator.translate(from: codeGenerationRequest)
  769. let renderer = TextBasedRenderer.default
  770. renderer.renderCodeBlocks(codeBlocks)
  771. let contents = renderer.renderedContents()
  772. try XCTAssertEqualWithDiff(contents, expectedSwift, file: file, line: line)
  773. }
  774. }
  775. #endif // os(macOS) || os(Linux)