ClientCodeTranslatorSnippetBasedTests.swift 29 KB

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