ClientCodeTranslatorSnippetBasedTests.swift 27 KB

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