ClientCodeTranslatorSnippetBasedTests.swift 36 KB

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