ProtobufCodeGeneratorTests.swift 17 KB

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