2
0

ProtobufCodeGeneratorTests.swift 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /*
  2. * Copyright 2024, 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 GRPCCodeGen
  18. import GRPCProtobufCodeGen
  19. import SwiftProtobuf
  20. import SwiftProtobufPluginLibrary
  21. import XCTest
  22. final class ProtobufCodeGeneratorTests: XCTestCase {
  23. func testProtobufCodeGenerator() throws {
  24. try testCodeGeneration(
  25. indentation: 4,
  26. visibility: .internal,
  27. client: true,
  28. server: false,
  29. expectedCode: """
  30. // Copyright 2015 gRPC authors.
  31. //
  32. // Licensed under the Apache License, Version 2.0 (the "License");
  33. // you may not use this file except in compliance with the License.
  34. // You may obtain a copy of the License at
  35. //
  36. // http://www.apache.org/licenses/LICENSE-2.0
  37. //
  38. // Unless required by applicable law or agreed to in writing, software
  39. // distributed under the License is distributed on an "AS IS" BASIS,
  40. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  41. // See the License for the specific language governing permissions and
  42. // limitations under the License.
  43. // DO NOT EDIT.
  44. // swift-format-ignore-file
  45. //
  46. // Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
  47. // Source: helloworld.proto
  48. //
  49. // For information on using the generated types, please see the documentation:
  50. // https://github.com/grpc/grpc-swift
  51. import GRPCCore
  52. import GRPCProtobuf
  53. internal enum Helloworld {
  54. internal enum Greeter {
  55. internal enum Method {
  56. internal enum SayHello {
  57. internal typealias Input = Helloworld_HelloRequest
  58. internal typealias Output = Helloworld_HelloReply
  59. internal static let descriptor = MethodDescriptor(
  60. service: "helloworld.Greeter",
  61. method: "SayHello"
  62. )
  63. }
  64. internal static let descriptors: [MethodDescriptor] = [
  65. Helloworld.Greeter.Method.SayHello.descriptor
  66. ]
  67. }
  68. internal typealias ClientProtocol = Helloworld_GreeterClientProtocol
  69. internal typealias Client = Helloworld_GreeterClient
  70. }
  71. }
  72. /// The greeting service definition.
  73. internal protocol Helloworld_GreeterClientProtocol: Sendable {
  74. /// Sends a greeting.
  75. func sayHello<R>(
  76. request: ClientRequest.Single<Helloworld.Greeter.Method.SayHello.Input>,
  77. serializer: some MessageSerializer<Helloworld.Greeter.Method.SayHello.Input>,
  78. deserializer: some MessageDeserializer<Helloworld.Greeter.Method.SayHello.Output>,
  79. _ body: @Sendable @escaping (ClientResponse.Single<Helloworld.Greeter.Method.SayHello.Output>) async throws -> R
  80. ) async throws -> R where R: Sendable
  81. }
  82. extension Helloworld.Greeter.ClientProtocol {
  83. internal func sayHello<R>(
  84. request: ClientRequest.Single<Helloworld.Greeter.Method.SayHello.Input>,
  85. _ body: @Sendable @escaping (ClientResponse.Single<Helloworld.Greeter.Method.SayHello.Output>) async throws -> R
  86. ) async throws -> R where R: Sendable {
  87. try await self.sayHello(
  88. request: request,
  89. serializer: ProtobufSerializer<Helloworld.Greeter.Method.SayHello.Input>(),
  90. deserializer: ProtobufDeserializer<Helloworld.Greeter.Method.SayHello.Output>(),
  91. body
  92. )
  93. }
  94. }
  95. /// The greeting service definition.
  96. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  97. internal struct Helloworld_GreeterClient: Helloworld.Greeter.ClientProtocol {
  98. private let client: GRPCCore.GRPCClient
  99. internal init(client: GRPCCore.GRPCClient) {
  100. self.client = client
  101. }
  102. /// Sends a greeting.
  103. internal func sayHello<R>(
  104. request: ClientRequest.Single<Helloworld.Greeter.Method.SayHello.Input>,
  105. serializer: some MessageSerializer<Helloworld.Greeter.Method.SayHello.Input>,
  106. deserializer: some MessageDeserializer<Helloworld.Greeter.Method.SayHello.Output>,
  107. _ body: @Sendable @escaping (ClientResponse.Single<Helloworld.Greeter.Method.SayHello.Output>) async throws -> R
  108. ) async throws -> R where R: Sendable {
  109. try await self.client.unary(
  110. request: request,
  111. descriptor: Helloworld.Greeter.Method.SayHello.descriptor,
  112. serializer: serializer,
  113. deserializer: deserializer,
  114. handler: body
  115. )
  116. }
  117. }
  118. """
  119. )
  120. try testCodeGeneration(
  121. indentation: 2,
  122. visibility: .public,
  123. client: false,
  124. server: true,
  125. expectedCode: """
  126. // Copyright 2015 gRPC authors.
  127. //
  128. // Licensed under the Apache License, Version 2.0 (the "License");
  129. // you may not use this file except in compliance with the License.
  130. // You may obtain a copy of the License at
  131. //
  132. // http://www.apache.org/licenses/LICENSE-2.0
  133. //
  134. // Unless required by applicable law or agreed to in writing, software
  135. // distributed under the License is distributed on an "AS IS" BASIS,
  136. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  137. // See the License for the specific language governing permissions and
  138. // limitations under the License.
  139. // DO NOT EDIT.
  140. // swift-format-ignore-file
  141. //
  142. // Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
  143. // Source: helloworld.proto
  144. //
  145. // For information on using the generated types, please see the documentation:
  146. // https://github.com/grpc/grpc-swift
  147. import GRPCCore
  148. import GRPCProtobuf
  149. public enum Helloworld {
  150. public enum Greeter {
  151. public enum Method {
  152. public enum SayHello {
  153. public typealias Input = Helloworld_HelloRequest
  154. public typealias Output = Helloworld_HelloReply
  155. public static let descriptor = MethodDescriptor(
  156. service: "helloworld.Greeter",
  157. method: "SayHello"
  158. )
  159. }
  160. public static let descriptors: [MethodDescriptor] = [
  161. Helloworld.Greeter.Method.SayHello.descriptor
  162. ]
  163. }
  164. public typealias StreamingServiceProtocol = Helloworld_GreeterStreamingServiceProtocol
  165. public typealias ServiceProtocol = Helloworld_GreeterServiceProtocol
  166. }
  167. }
  168. /// The greeting service definition.
  169. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  170. public protocol Helloworld_GreeterStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  171. /// Sends a greeting.
  172. func sayHello(request: ServerRequest.Stream<Helloworld.Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Stream<Helloworld.Greeter.Method.SayHello.Output>
  173. }
  174. /// Conformance to `GRPCCore.RegistrableRPCService`.
  175. extension Helloworld.Greeter.StreamingServiceProtocol {
  176. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  177. public func registerMethods(with router: inout GRPCCore.RPCRouter) {
  178. router.registerHandler(
  179. forMethod: Helloworld.Greeter.Method.SayHello.descriptor,
  180. deserializer: ProtobufDeserializer<Helloworld.Greeter.Method.SayHello.Input>(),
  181. serializer: ProtobufSerializer<Helloworld.Greeter.Method.SayHello.Output>(),
  182. handler: { request in
  183. try await self.sayHello(request: request)
  184. }
  185. )
  186. }
  187. }
  188. /// The greeting service definition.
  189. public protocol Helloworld_GreeterServiceProtocol: Helloworld.Greeter.StreamingServiceProtocol {
  190. /// Sends a greeting.
  191. func sayHello(request: ServerRequest.Single<Helloworld.Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Single<Helloworld.Greeter.Method.SayHello.Output>
  192. }
  193. /// Partial conformance to `Helloworld_GreeterStreamingServiceProtocol`.
  194. extension Helloworld.Greeter.ServiceProtocol {
  195. public func sayHello(request: ServerRequest.Stream<Helloworld.Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Stream<Helloworld.Greeter.Method.SayHello.Output> {
  196. let response = try await self.sayHello(request: ServerRequest.Single(stream: request))
  197. return ServerResponse.Stream(single: response)
  198. }
  199. }
  200. """
  201. )
  202. try testCodeGeneration(
  203. indentation: 2,
  204. visibility: .package,
  205. client: true,
  206. server: true,
  207. expectedCode: """
  208. // Copyright 2015 gRPC authors.
  209. //
  210. // Licensed under the Apache License, Version 2.0 (the "License");
  211. // you may not use this file except in compliance with the License.
  212. // You may obtain a copy of the License at
  213. //
  214. // http://www.apache.org/licenses/LICENSE-2.0
  215. //
  216. // Unless required by applicable law or agreed to in writing, software
  217. // distributed under the License is distributed on an "AS IS" BASIS,
  218. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  219. // See the License for the specific language governing permissions and
  220. // limitations under the License.
  221. // DO NOT EDIT.
  222. // swift-format-ignore-file
  223. //
  224. // Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
  225. // Source: helloworld.proto
  226. //
  227. // For information on using the generated types, please see the documentation:
  228. // https://github.com/grpc/grpc-swift
  229. import GRPCCore
  230. import GRPCProtobuf
  231. package enum Helloworld {
  232. package enum Greeter {
  233. package enum Method {
  234. package enum SayHello {
  235. package typealias Input = Helloworld_HelloRequest
  236. package typealias Output = Helloworld_HelloReply
  237. package static let descriptor = MethodDescriptor(
  238. service: "helloworld.Greeter",
  239. method: "SayHello"
  240. )
  241. }
  242. package static let descriptors: [MethodDescriptor] = [
  243. Helloworld.Greeter.Method.SayHello.descriptor
  244. ]
  245. }
  246. package typealias StreamingServiceProtocol = Helloworld_GreeterStreamingServiceProtocol
  247. package typealias ServiceProtocol = Helloworld_GreeterServiceProtocol
  248. package typealias ClientProtocol = Helloworld_GreeterClientProtocol
  249. package typealias Client = Helloworld_GreeterClient
  250. }
  251. }
  252. /// The greeting service definition.
  253. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  254. package protocol Helloworld_GreeterStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  255. /// Sends a greeting.
  256. func sayHello(request: ServerRequest.Stream<Helloworld.Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Stream<Helloworld.Greeter.Method.SayHello.Output>
  257. }
  258. /// Conformance to `GRPCCore.RegistrableRPCService`.
  259. extension Helloworld.Greeter.StreamingServiceProtocol {
  260. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  261. package func registerMethods(with router: inout GRPCCore.RPCRouter) {
  262. router.registerHandler(
  263. forMethod: Helloworld.Greeter.Method.SayHello.descriptor,
  264. deserializer: ProtobufDeserializer<Helloworld.Greeter.Method.SayHello.Input>(),
  265. serializer: ProtobufSerializer<Helloworld.Greeter.Method.SayHello.Output>(),
  266. handler: { request in
  267. try await self.sayHello(request: request)
  268. }
  269. )
  270. }
  271. }
  272. /// The greeting service definition.
  273. package protocol Helloworld_GreeterServiceProtocol: Helloworld.Greeter.StreamingServiceProtocol {
  274. /// Sends a greeting.
  275. func sayHello(request: ServerRequest.Single<Helloworld.Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Single<Helloworld.Greeter.Method.SayHello.Output>
  276. }
  277. /// Partial conformance to `Helloworld_GreeterStreamingServiceProtocol`.
  278. extension Helloworld.Greeter.ServiceProtocol {
  279. package func sayHello(request: ServerRequest.Stream<Helloworld.Greeter.Method.SayHello.Input>) async throws -> ServerResponse.Stream<Helloworld.Greeter.Method.SayHello.Output> {
  280. let response = try await self.sayHello(request: ServerRequest.Single(stream: request))
  281. return ServerResponse.Stream(single: response)
  282. }
  283. }
  284. /// The greeting service definition.
  285. package protocol Helloworld_GreeterClientProtocol: Sendable {
  286. /// Sends a greeting.
  287. func sayHello<R>(
  288. request: ClientRequest.Single<Helloworld.Greeter.Method.SayHello.Input>,
  289. serializer: some MessageSerializer<Helloworld.Greeter.Method.SayHello.Input>,
  290. deserializer: some MessageDeserializer<Helloworld.Greeter.Method.SayHello.Output>,
  291. _ body: @Sendable @escaping (ClientResponse.Single<Helloworld.Greeter.Method.SayHello.Output>) async throws -> R
  292. ) async throws -> R where R: Sendable
  293. }
  294. extension Helloworld.Greeter.ClientProtocol {
  295. package func sayHello<R>(
  296. request: ClientRequest.Single<Helloworld.Greeter.Method.SayHello.Input>,
  297. _ body: @Sendable @escaping (ClientResponse.Single<Helloworld.Greeter.Method.SayHello.Output>) async throws -> R
  298. ) async throws -> R where R: Sendable {
  299. try await self.sayHello(
  300. request: request,
  301. serializer: ProtobufSerializer<Helloworld.Greeter.Method.SayHello.Input>(),
  302. deserializer: ProtobufDeserializer<Helloworld.Greeter.Method.SayHello.Output>(),
  303. body
  304. )
  305. }
  306. }
  307. /// The greeting service definition.
  308. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  309. package struct Helloworld_GreeterClient: Helloworld.Greeter.ClientProtocol {
  310. private let client: GRPCCore.GRPCClient
  311. package init(client: GRPCCore.GRPCClient) {
  312. self.client = client
  313. }
  314. /// Sends a greeting.
  315. package func sayHello<R>(
  316. request: ClientRequest.Single<Helloworld.Greeter.Method.SayHello.Input>,
  317. serializer: some MessageSerializer<Helloworld.Greeter.Method.SayHello.Input>,
  318. deserializer: some MessageDeserializer<Helloworld.Greeter.Method.SayHello.Output>,
  319. _ body: @Sendable @escaping (ClientResponse.Single<Helloworld.Greeter.Method.SayHello.Output>) async throws -> R
  320. ) async throws -> R where R: Sendable {
  321. try await self.client.unary(
  322. request: request,
  323. descriptor: Helloworld.Greeter.Method.SayHello.descriptor,
  324. serializer: serializer,
  325. deserializer: deserializer,
  326. handler: body
  327. )
  328. }
  329. }
  330. """
  331. )
  332. }
  333. func testCodeGeneration(
  334. indentation: Int,
  335. visibility: SourceGenerator.Configuration.AccessLevel,
  336. client: Bool,
  337. server: Bool,
  338. expectedCode: String
  339. ) throws {
  340. let configs = SourceGenerator.Configuration(
  341. accessLevel: visibility,
  342. client: client,
  343. server: server,
  344. indentation: indentation
  345. )
  346. let descriptorSet = DescriptorSet(protos: [Google_Protobuf_FileDescriptorProto.helloWorld])
  347. guard let fileDescriptor = descriptorSet.fileDescriptor(named: "helloworld.proto") else {
  348. return XCTFail(
  349. """
  350. Could not find the file descriptor of "helloworld.proto".
  351. """
  352. )
  353. }
  354. let generator = ProtobufCodeGenerator(configuration: configs)
  355. try XCTAssertEqualWithDiff(
  356. try generator.generateCode(
  357. from: fileDescriptor,
  358. protoFileModuleMappings: ProtoFileToModuleMappings()
  359. ),
  360. expectedCode
  361. )
  362. }
  363. }
  364. private func diff(expected: String, actual: String) throws -> String {
  365. let process = Process()
  366. process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
  367. process.arguments = [
  368. "bash", "-c",
  369. "diff -U5 --label=expected <(echo '\(expected)') --label=actual <(echo '\(actual)')",
  370. ]
  371. let pipe = Pipe()
  372. process.standardOutput = pipe
  373. try process.run()
  374. process.waitUntilExit()
  375. let pipeData = try XCTUnwrap(
  376. pipe.fileHandleForReading.readToEnd(),
  377. """
  378. No output from command:
  379. \(process.executableURL!.path) \(process.arguments!.joined(separator: " "))
  380. """
  381. )
  382. return String(decoding: pipeData, as: UTF8.self)
  383. }
  384. internal func XCTAssertEqualWithDiff(
  385. _ actual: String,
  386. _ expected: String,
  387. file: StaticString = #filePath,
  388. line: UInt = #line
  389. ) throws {
  390. if actual == expected { return }
  391. XCTFail(
  392. """
  393. XCTAssertEqualWithDiff failed (click for diff)
  394. \(try diff(expected: expected, actual: actual))
  395. """,
  396. file: file,
  397. line: line
  398. )
  399. }
  400. #endif // os(macOS) || os(Linux)