ProtobufCodeGeneratorTests.swift 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  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. proto: Google_Protobuf_FileDescriptorProto.helloWorldNestedPackage,
  26. indentation: 4,
  27. visibility: .internal,
  28. client: true,
  29. server: false,
  30. expectedCode: """
  31. // Copyright 2015 gRPC authors.
  32. //
  33. // Licensed under the Apache License, Version 2.0 (the "License");
  34. // you may not use this file except in compliance with the License.
  35. // You may obtain a copy of the License at
  36. //
  37. // http://www.apache.org/licenses/LICENSE-2.0
  38. //
  39. // Unless required by applicable law or agreed to in writing, software
  40. // distributed under the License is distributed on an "AS IS" BASIS,
  41. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  42. // See the License for the specific language governing permissions and
  43. // limitations under the License.
  44. // DO NOT EDIT.
  45. // swift-format-ignore-file
  46. //
  47. // Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
  48. // Source: helloworld.proto
  49. //
  50. // For information on using the generated types, please see the documentation:
  51. // https://github.com/grpc/grpc-swift
  52. internal import GRPCCore
  53. internal import GRPCProtobuf
  54. internal import DifferentModule
  55. internal import ExtraModule
  56. internal enum Hello_World_Greeter {
  57. internal static let descriptor = GRPCCore.ServiceDescriptor.hello_world_Greeter
  58. internal enum Method {
  59. internal enum SayHello {
  60. internal typealias Input = Hello_World_HelloRequest
  61. internal typealias Output = Hello_World_HelloReply
  62. internal static let descriptor = GRPCCore.MethodDescriptor(
  63. service: Hello_World_Greeter.descriptor.fullyQualifiedService,
  64. method: "SayHello"
  65. )
  66. }
  67. internal static let descriptors: [GRPCCore.MethodDescriptor] = [
  68. SayHello.descriptor
  69. ]
  70. }
  71. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  72. internal typealias ClientProtocol = Hello_World_GreeterClientProtocol
  73. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  74. internal typealias Client = Hello_World_GreeterClient
  75. }
  76. extension GRPCCore.ServiceDescriptor {
  77. internal static let hello_world_Greeter = Self(
  78. package: "hello.world",
  79. service: "Greeter"
  80. )
  81. }
  82. /// The greeting service definition.
  83. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  84. internal protocol Hello_World_GreeterClientProtocol: Sendable {
  85. /// Sends a greeting.
  86. func sayHello<R>(
  87. request: GRPCCore.ClientRequest.Single<Hello_World_HelloRequest>,
  88. serializer: some GRPCCore.MessageSerializer<Hello_World_HelloRequest>,
  89. deserializer: some GRPCCore.MessageDeserializer<Hello_World_HelloReply>,
  90. options: GRPCCore.CallOptions,
  91. _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single<Hello_World_HelloReply>) async throws -> R
  92. ) async throws -> R where R: Sendable
  93. }
  94. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  95. extension Hello_World_Greeter.ClientProtocol {
  96. internal func sayHello<R>(
  97. request: GRPCCore.ClientRequest.Single<Hello_World_HelloRequest>,
  98. options: GRPCCore.CallOptions = .defaults,
  99. _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single<Hello_World_HelloReply>) async throws -> R = {
  100. try $0.message
  101. }
  102. ) async throws -> R where R: Sendable {
  103. try await self.sayHello(
  104. request: request,
  105. serializer: GRPCProtobuf.ProtobufSerializer<Hello_World_HelloRequest>(),
  106. deserializer: GRPCProtobuf.ProtobufDeserializer<Hello_World_HelloReply>(),
  107. options: options,
  108. body
  109. )
  110. }
  111. }
  112. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  113. extension Hello_World_Greeter.ClientProtocol {
  114. /// Sends a greeting.
  115. internal func sayHello<Result>(
  116. _ message: Hello_World_HelloRequest,
  117. metadata: GRPCCore.Metadata = [:],
  118. options: GRPCCore.CallOptions = .defaults,
  119. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single<Hello_World_HelloReply>) async throws -> Result = {
  120. try $0.message
  121. }
  122. ) async throws -> Result where Result: Sendable {
  123. let request = GRPCCore.ClientRequest.Single<Hello_World_HelloRequest>(
  124. message: message,
  125. metadata: metadata
  126. )
  127. return try await self.sayHello(
  128. request: request,
  129. options: options,
  130. handleResponse
  131. )
  132. }
  133. }
  134. /// The greeting service definition.
  135. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  136. internal struct Hello_World_GreeterClient: Hello_World_Greeter.ClientProtocol {
  137. private let client: GRPCCore.GRPCClient
  138. internal init(wrapping client: GRPCCore.GRPCClient) {
  139. self.client = client
  140. }
  141. /// Sends a greeting.
  142. internal func sayHello<R>(
  143. request: GRPCCore.ClientRequest.Single<Hello_World_HelloRequest>,
  144. serializer: some GRPCCore.MessageSerializer<Hello_World_HelloRequest>,
  145. deserializer: some GRPCCore.MessageDeserializer<Hello_World_HelloReply>,
  146. options: GRPCCore.CallOptions = .defaults,
  147. _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single<Hello_World_HelloReply>) async throws -> R = {
  148. try $0.message
  149. }
  150. ) async throws -> R where R: Sendable {
  151. try await self.client.unary(
  152. request: request,
  153. descriptor: Hello_World_Greeter.Method.SayHello.descriptor,
  154. serializer: serializer,
  155. deserializer: deserializer,
  156. options: options,
  157. handler: body
  158. )
  159. }
  160. }
  161. """
  162. )
  163. try testCodeGeneration(
  164. proto: Google_Protobuf_FileDescriptorProto.helloWorld,
  165. indentation: 2,
  166. visibility: .public,
  167. client: false,
  168. server: true,
  169. expectedCode: """
  170. // Copyright 2015 gRPC authors.
  171. //
  172. // Licensed under the Apache License, Version 2.0 (the "License");
  173. // you may not use this file except in compliance with the License.
  174. // You may obtain a copy of the License at
  175. //
  176. // http://www.apache.org/licenses/LICENSE-2.0
  177. //
  178. // Unless required by applicable law or agreed to in writing, software
  179. // distributed under the License is distributed on an "AS IS" BASIS,
  180. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  181. // See the License for the specific language governing permissions and
  182. // limitations under the License.
  183. // DO NOT EDIT.
  184. // swift-format-ignore-file
  185. //
  186. // Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
  187. // Source: helloworld.proto
  188. //
  189. // For information on using the generated types, please see the documentation:
  190. // https://github.com/grpc/grpc-swift
  191. public import GRPCCore
  192. internal import GRPCProtobuf
  193. public import DifferentModule
  194. public import ExtraModule
  195. public enum Helloworld_Greeter {
  196. public static let descriptor = GRPCCore.ServiceDescriptor.helloworld_Greeter
  197. public enum Method {
  198. public enum SayHello {
  199. public typealias Input = Helloworld_HelloRequest
  200. public typealias Output = Helloworld_HelloReply
  201. public static let descriptor = GRPCCore.MethodDescriptor(
  202. service: Helloworld_Greeter.descriptor.fullyQualifiedService,
  203. method: "SayHello"
  204. )
  205. }
  206. public static let descriptors: [GRPCCore.MethodDescriptor] = [
  207. SayHello.descriptor
  208. ]
  209. }
  210. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  211. public typealias StreamingServiceProtocol = Helloworld_GreeterStreamingServiceProtocol
  212. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  213. public typealias ServiceProtocol = Helloworld_GreeterServiceProtocol
  214. }
  215. extension GRPCCore.ServiceDescriptor {
  216. public static let helloworld_Greeter = Self(
  217. package: "helloworld",
  218. service: "Greeter"
  219. )
  220. }
  221. /// The greeting service definition.
  222. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  223. public protocol Helloworld_GreeterStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  224. /// Sends a greeting.
  225. func sayHello(
  226. request: GRPCCore.ServerRequest.Stream<Helloworld_HelloRequest>,
  227. context: GRPCCore.ServerContext
  228. ) async throws -> GRPCCore.ServerResponse.Stream<Helloworld_HelloReply>
  229. }
  230. /// Conformance to `GRPCCore.RegistrableRPCService`.
  231. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  232. extension Helloworld_Greeter.StreamingServiceProtocol {
  233. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  234. public func registerMethods(with router: inout GRPCCore.RPCRouter) {
  235. router.registerHandler(
  236. forMethod: Helloworld_Greeter.Method.SayHello.descriptor,
  237. deserializer: GRPCProtobuf.ProtobufDeserializer<Helloworld_HelloRequest>(),
  238. serializer: GRPCProtobuf.ProtobufSerializer<Helloworld_HelloReply>(),
  239. handler: { request, context in
  240. try await self.sayHello(
  241. request: request,
  242. context: context
  243. )
  244. }
  245. )
  246. }
  247. }
  248. /// The greeting service definition.
  249. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  250. public protocol Helloworld_GreeterServiceProtocol: Helloworld_Greeter.StreamingServiceProtocol {
  251. /// Sends a greeting.
  252. func sayHello(
  253. request: GRPCCore.ServerRequest.Single<Helloworld_HelloRequest>,
  254. context: GRPCCore.ServerContext
  255. ) async throws -> GRPCCore.ServerResponse.Single<Helloworld_HelloReply>
  256. }
  257. /// Partial conformance to `Helloworld_GreeterStreamingServiceProtocol`.
  258. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  259. extension Helloworld_Greeter.ServiceProtocol {
  260. public func sayHello(
  261. request: GRPCCore.ServerRequest.Stream<Helloworld_HelloRequest>,
  262. context: GRPCCore.ServerContext
  263. ) async throws -> GRPCCore.ServerResponse.Stream<Helloworld_HelloReply> {
  264. let response = try await self.sayHello(
  265. request: GRPCCore.ServerRequest.Single(stream: request),
  266. context: context
  267. )
  268. return GRPCCore.ServerResponse.Stream(single: response)
  269. }
  270. }
  271. """
  272. )
  273. try testCodeGeneration(
  274. proto: Google_Protobuf_FileDescriptorProto.helloWorldEmptyPackage,
  275. indentation: 2,
  276. visibility: .package,
  277. client: true,
  278. server: true,
  279. expectedCode: """
  280. // Copyright 2015 gRPC authors.
  281. //
  282. // Licensed under the Apache License, Version 2.0 (the "License");
  283. // you may not use this file except in compliance with the License.
  284. // You may obtain a copy of the License at
  285. //
  286. // http://www.apache.org/licenses/LICENSE-2.0
  287. //
  288. // Unless required by applicable law or agreed to in writing, software
  289. // distributed under the License is distributed on an "AS IS" BASIS,
  290. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  291. // See the License for the specific language governing permissions and
  292. // limitations under the License.
  293. // DO NOT EDIT.
  294. // swift-format-ignore-file
  295. //
  296. // Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
  297. // Source: helloworld.proto
  298. //
  299. // For information on using the generated types, please see the documentation:
  300. // https://github.com/grpc/grpc-swift
  301. package import GRPCCore
  302. internal import GRPCProtobuf
  303. package import DifferentModule
  304. package import ExtraModule
  305. package enum Greeter {
  306. package static let descriptor = GRPCCore.ServiceDescriptor.Greeter
  307. package enum Method {
  308. package enum SayHello {
  309. package typealias Input = HelloRequest
  310. package typealias Output = HelloReply
  311. package static let descriptor = GRPCCore.MethodDescriptor(
  312. service: Greeter.descriptor.fullyQualifiedService,
  313. method: "SayHello"
  314. )
  315. }
  316. package static let descriptors: [GRPCCore.MethodDescriptor] = [
  317. SayHello.descriptor
  318. ]
  319. }
  320. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  321. package typealias StreamingServiceProtocol = GreeterStreamingServiceProtocol
  322. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  323. package typealias ServiceProtocol = GreeterServiceProtocol
  324. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  325. package typealias ClientProtocol = GreeterClientProtocol
  326. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  327. package typealias Client = GreeterClient
  328. }
  329. extension GRPCCore.ServiceDescriptor {
  330. package static let Greeter = Self(
  331. package: "",
  332. service: "Greeter"
  333. )
  334. }
  335. /// The greeting service definition.
  336. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  337. package protocol GreeterStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  338. /// Sends a greeting.
  339. func sayHello(
  340. request: GRPCCore.ServerRequest.Stream<HelloRequest>,
  341. context: GRPCCore.ServerContext
  342. ) async throws -> GRPCCore.ServerResponse.Stream<HelloReply>
  343. }
  344. /// Conformance to `GRPCCore.RegistrableRPCService`.
  345. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  346. extension Greeter.StreamingServiceProtocol {
  347. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  348. package func registerMethods(with router: inout GRPCCore.RPCRouter) {
  349. router.registerHandler(
  350. forMethod: Greeter.Method.SayHello.descriptor,
  351. deserializer: GRPCProtobuf.ProtobufDeserializer<HelloRequest>(),
  352. serializer: GRPCProtobuf.ProtobufSerializer<HelloReply>(),
  353. handler: { request, context in
  354. try await self.sayHello(
  355. request: request,
  356. context: context
  357. )
  358. }
  359. )
  360. }
  361. }
  362. /// The greeting service definition.
  363. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  364. package protocol GreeterServiceProtocol: Greeter.StreamingServiceProtocol {
  365. /// Sends a greeting.
  366. func sayHello(
  367. request: GRPCCore.ServerRequest.Single<HelloRequest>,
  368. context: GRPCCore.ServerContext
  369. ) async throws -> GRPCCore.ServerResponse.Single<HelloReply>
  370. }
  371. /// Partial conformance to `GreeterStreamingServiceProtocol`.
  372. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  373. extension Greeter.ServiceProtocol {
  374. package func sayHello(
  375. request: GRPCCore.ServerRequest.Stream<HelloRequest>,
  376. context: GRPCCore.ServerContext
  377. ) async throws -> GRPCCore.ServerResponse.Stream<HelloReply> {
  378. let response = try await self.sayHello(
  379. request: GRPCCore.ServerRequest.Single(stream: request),
  380. context: context
  381. )
  382. return GRPCCore.ServerResponse.Stream(single: response)
  383. }
  384. }
  385. /// The greeting service definition.
  386. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  387. package protocol GreeterClientProtocol: Sendable {
  388. /// Sends a greeting.
  389. func sayHello<R>(
  390. request: GRPCCore.ClientRequest.Single<HelloRequest>,
  391. serializer: some GRPCCore.MessageSerializer<HelloRequest>,
  392. deserializer: some GRPCCore.MessageDeserializer<HelloReply>,
  393. options: GRPCCore.CallOptions,
  394. _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single<HelloReply>) async throws -> R
  395. ) async throws -> R where R: Sendable
  396. }
  397. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  398. extension Greeter.ClientProtocol {
  399. package func sayHello<R>(
  400. request: GRPCCore.ClientRequest.Single<HelloRequest>,
  401. options: GRPCCore.CallOptions = .defaults,
  402. _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single<HelloReply>) async throws -> R = {
  403. try $0.message
  404. }
  405. ) async throws -> R where R: Sendable {
  406. try await self.sayHello(
  407. request: request,
  408. serializer: GRPCProtobuf.ProtobufSerializer<HelloRequest>(),
  409. deserializer: GRPCProtobuf.ProtobufDeserializer<HelloReply>(),
  410. options: options,
  411. body
  412. )
  413. }
  414. }
  415. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  416. extension Greeter.ClientProtocol {
  417. /// Sends a greeting.
  418. package func sayHello<Result>(
  419. _ message: HelloRequest,
  420. metadata: GRPCCore.Metadata = [:],
  421. options: GRPCCore.CallOptions = .defaults,
  422. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single<HelloReply>) async throws -> Result = {
  423. try $0.message
  424. }
  425. ) async throws -> Result where Result: Sendable {
  426. let request = GRPCCore.ClientRequest.Single<HelloRequest>(
  427. message: message,
  428. metadata: metadata
  429. )
  430. return try await self.sayHello(
  431. request: request,
  432. options: options,
  433. handleResponse
  434. )
  435. }
  436. }
  437. /// The greeting service definition.
  438. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  439. package struct GreeterClient: Greeter.ClientProtocol {
  440. private let client: GRPCCore.GRPCClient
  441. package init(wrapping client: GRPCCore.GRPCClient) {
  442. self.client = client
  443. }
  444. /// Sends a greeting.
  445. package func sayHello<R>(
  446. request: GRPCCore.ClientRequest.Single<HelloRequest>,
  447. serializer: some GRPCCore.MessageSerializer<HelloRequest>,
  448. deserializer: some GRPCCore.MessageDeserializer<HelloReply>,
  449. options: GRPCCore.CallOptions = .defaults,
  450. _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single<HelloReply>) async throws -> R = {
  451. try $0.message
  452. }
  453. ) async throws -> R where R: Sendable {
  454. try await self.client.unary(
  455. request: request,
  456. descriptor: Greeter.Method.SayHello.descriptor,
  457. serializer: serializer,
  458. deserializer: deserializer,
  459. options: options,
  460. handler: body
  461. )
  462. }
  463. }
  464. """
  465. )
  466. }
  467. func testNoAccessLevelOnImports() throws {
  468. let proto = Google_Protobuf_FileDescriptorProto(name: "helloworld.proto", package: "")
  469. try testCodeGeneration(
  470. proto: proto,
  471. indentation: 2,
  472. visibility: .package,
  473. client: true,
  474. server: true,
  475. accessLevelOnImports: false,
  476. expectedCode: """
  477. // DO NOT EDIT.
  478. // swift-format-ignore-file
  479. //
  480. // Generated by the gRPC Swift generator plugin for the protocol buffer compiler.
  481. // Source: helloworld.proto
  482. //
  483. // For information on using the generated types, please see the documentation:
  484. // https://github.com/grpc/grpc-swift
  485. import GRPCCore
  486. import GRPCProtobuf
  487. import ExtraModule
  488. """
  489. )
  490. }
  491. func testCodeGeneration(
  492. proto: Google_Protobuf_FileDescriptorProto,
  493. indentation: Int,
  494. visibility: SourceGenerator.Config.AccessLevel,
  495. client: Bool,
  496. server: Bool,
  497. accessLevelOnImports: Bool = true,
  498. expectedCode: String,
  499. file: StaticString = #filePath,
  500. line: UInt = #line
  501. ) throws {
  502. let config = SourceGenerator.Config(
  503. accessLevel: visibility,
  504. accessLevelOnImports: accessLevelOnImports,
  505. client: client,
  506. server: server,
  507. indentation: indentation
  508. )
  509. let descriptorSet = DescriptorSet(
  510. protos: [
  511. Google_Protobuf_FileDescriptorProto(name: "same-module.proto", package: "same-package"),
  512. Google_Protobuf_FileDescriptorProto(
  513. name: "different-module.proto",
  514. package: "different-package"
  515. ),
  516. proto,
  517. ])
  518. guard let fileDescriptor = descriptorSet.fileDescriptor(named: "helloworld.proto") else {
  519. return XCTFail(
  520. """
  521. Could not find the file descriptor of "helloworld.proto".
  522. """
  523. )
  524. }
  525. let moduleMappings = SwiftProtobuf_GenSwift_ModuleMappings.with {
  526. $0.mapping = [
  527. SwiftProtobuf_GenSwift_ModuleMappings.Entry.with {
  528. $0.protoFilePath = ["different-module.proto"]
  529. $0.moduleName = "DifferentModule"
  530. }
  531. ]
  532. }
  533. let generator = ProtobufCodeGenerator(configuration: config)
  534. try XCTAssertEqualWithDiff(
  535. try generator.generateCode(
  536. from: fileDescriptor,
  537. protoFileModuleMappings: ProtoFileToModuleMappings(moduleMappingsProto: moduleMappings),
  538. extraModuleImports: ["ExtraModule"]
  539. ),
  540. expectedCode,
  541. file: file,
  542. line: line
  543. )
  544. }
  545. }
  546. private func diff(expected: String, actual: String) throws -> String {
  547. let process = Process()
  548. process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
  549. process.arguments = [
  550. "bash", "-c",
  551. "diff -U5 --label=expected <(echo '\(expected)') --label=actual <(echo '\(actual)')",
  552. ]
  553. let pipe = Pipe()
  554. process.standardOutput = pipe
  555. try process.run()
  556. process.waitUntilExit()
  557. let pipeData = try XCTUnwrap(
  558. pipe.fileHandleForReading.readToEnd(),
  559. """
  560. No output from command:
  561. \(process.executableURL!.path) \(process.arguments!.joined(separator: " "))
  562. """
  563. )
  564. return String(decoding: pipeData, as: UTF8.self)
  565. }
  566. internal func XCTAssertEqualWithDiff(
  567. _ actual: String,
  568. _ expected: String,
  569. file: StaticString = #filePath,
  570. line: UInt = #line
  571. ) throws {
  572. if actual == expected { return }
  573. XCTFail(
  574. """
  575. XCTAssertEqualWithDiff failed (click for diff)
  576. \(try diff(expected: expected, actual: actual))
  577. """,
  578. file: file,
  579. line: line
  580. )
  581. }
  582. #endif // os(macOS) || os(Linux)