IDLToStructuredSwiftTranslatorSnippetBasedTests.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  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 XCTest
  18. @testable import GRPCCodeGen
  19. @available(gRPCSwift 2.0, *)
  20. final class IDLToStructuredSwiftTranslatorSnippetBasedTests: XCTestCase {
  21. func testGeneration() throws {
  22. var dependencies = [Dependency]()
  23. dependencies.append(
  24. Dependency(module: "Foo", spi: "Secret", accessLevel: .internal)
  25. )
  26. dependencies.append(
  27. Dependency(
  28. item: .init(kind: .enum, name: "Bar"),
  29. module: "Foo",
  30. spi: "Secret",
  31. accessLevel: .internal
  32. )
  33. )
  34. let serviceA = ServiceDescriptor(
  35. documentation: "/// Documentation for AService\n",
  36. name: ServiceName(
  37. identifyingName: "namespaceA.ServiceA",
  38. typeName: "NamespaceA_ServiceA",
  39. propertyName: "namespaceA_ServiceA"
  40. ),
  41. methods: []
  42. )
  43. let expectedSwift =
  44. """
  45. /// Some really exciting license header 2023.
  46. public import GRPCCore
  47. @_spi(Secret) internal import Foo
  48. @_spi(Secret) internal import enum Foo.Bar
  49. // MARK: - namespaceA.ServiceA
  50. /// Namespace containing generated types for the "namespaceA.ServiceA" service.
  51. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  52. public enum NamespaceA_ServiceA {
  53. /// Service descriptor for the "namespaceA.ServiceA" service.
  54. public static let descriptor = GRPCCore.ServiceDescriptor(fullyQualifiedService: "namespaceA.ServiceA")
  55. /// Namespace for method metadata.
  56. public enum Method {
  57. /// Descriptors for all methods in the "namespaceA.ServiceA" service.
  58. public static let descriptors: [GRPCCore.MethodDescriptor] = []
  59. }
  60. }
  61. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  62. extension GRPCCore.ServiceDescriptor {
  63. /// Service descriptor for the "namespaceA.ServiceA" service.
  64. public static let namespaceA_ServiceA = GRPCCore.ServiceDescriptor(fullyQualifiedService: "namespaceA.ServiceA")
  65. }
  66. // MARK: namespaceA.ServiceA (server)
  67. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  68. extension NamespaceA_ServiceA {
  69. /// Streaming variant of the service protocol for the "namespaceA.ServiceA" service.
  70. ///
  71. /// This protocol is the lowest-level of the service protocols generated for this service
  72. /// giving you the most flexibility over the implementation of your service. This comes at
  73. /// the cost of more verbose and less strict APIs. Each RPC requires you to implement it in
  74. /// terms of a request stream and response stream. Where only a single request or response
  75. /// message is expected, you are responsible for enforcing this invariant is maintained.
  76. ///
  77. /// Where possible, prefer using the stricter, less-verbose ``ServiceProtocol``
  78. /// or ``SimpleServiceProtocol`` instead.
  79. ///
  80. /// > Source IDL Documentation:
  81. /// >
  82. /// > Documentation for AService
  83. public protocol StreamingServiceProtocol: GRPCCore.RegistrableRPCService {}
  84. /// Service protocol for the "namespaceA.ServiceA" service.
  85. ///
  86. /// This protocol is higher level than ``StreamingServiceProtocol`` but lower level than
  87. /// the ``SimpleServiceProtocol``, it provides access to request and response metadata and
  88. /// trailing response metadata. If you don't need these then consider using
  89. /// the ``SimpleServiceProtocol``. If you need fine grained control over your RPCs then
  90. /// use ``StreamingServiceProtocol``.
  91. ///
  92. /// > Source IDL Documentation:
  93. /// >
  94. /// > Documentation for AService
  95. public protocol ServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol {}
  96. /// Simple service protocol for the "namespaceA.ServiceA" service.
  97. ///
  98. /// This is the highest level protocol for the service. The API is the easiest to use but
  99. /// doesn't provide access to request or response metadata. If you need access to these
  100. /// then use ``ServiceProtocol`` instead.
  101. ///
  102. /// > Source IDL Documentation:
  103. /// >
  104. /// > Documentation for AService
  105. public protocol SimpleServiceProtocol: NamespaceA_ServiceA.ServiceProtocol {}
  106. }
  107. // Default implementation of 'registerMethods(with:)'.
  108. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  109. extension NamespaceA_ServiceA.StreamingServiceProtocol {
  110. public func registerMethods<Transport>(with router: inout GRPCCore.RPCRouter<Transport>) where Transport: GRPCCore.ServerTransport {}
  111. }
  112. // Default implementation of streaming methods from 'StreamingServiceProtocol'.
  113. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  114. extension NamespaceA_ServiceA.ServiceProtocol {
  115. }
  116. // Default implementation of methods from 'ServiceProtocol'.
  117. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  118. extension NamespaceA_ServiceA.SimpleServiceProtocol {
  119. }
  120. """
  121. try self.assertIDLToStructuredSwiftTranslation(
  122. codeGenerationRequest: makeCodeGenerationRequest(
  123. services: [serviceA],
  124. dependencies: dependencies
  125. ),
  126. expectedSwift: expectedSwift,
  127. accessLevel: .public,
  128. server: true
  129. )
  130. }
  131. func testGenerateWithDifferentModuleName() throws {
  132. let service = ServiceDescriptor(
  133. documentation: "/// Documentation for FooService\n",
  134. name: ServiceName(
  135. identifyingName: "foo.FooService",
  136. typeName: "Foo_FooService",
  137. propertyName: "foo_FooService"
  138. ),
  139. methods: [
  140. MethodDescriptor(
  141. documentation: "",
  142. name: MethodName(
  143. identifyingName: "Unary",
  144. typeName: "Unary",
  145. functionName: "unary"
  146. ),
  147. isInputStreaming: false,
  148. isOutputStreaming: false,
  149. inputType: "Foo",
  150. outputType: "Bar"
  151. ),
  152. MethodDescriptor(
  153. documentation: "",
  154. name: MethodName(
  155. identifyingName: "ClientStreaming",
  156. typeName: "ClientStreaming",
  157. functionName: "clientStreaming"
  158. ),
  159. isInputStreaming: true,
  160. isOutputStreaming: false,
  161. inputType: "Foo",
  162. outputType: "Bar"
  163. ),
  164. MethodDescriptor(
  165. documentation: "",
  166. name: MethodName(
  167. identifyingName: "ServerStreaming",
  168. typeName: "ServerStreaming",
  169. functionName: "serverStreaming"
  170. ),
  171. isInputStreaming: false,
  172. isOutputStreaming: true,
  173. inputType: "Foo",
  174. outputType: "Bar"
  175. ),
  176. MethodDescriptor(
  177. documentation: "",
  178. name: MethodName(
  179. identifyingName: "BidiStreaming",
  180. typeName: "BidiStreaming",
  181. functionName: "bidiStreaming"
  182. ),
  183. isInputStreaming: true,
  184. isOutputStreaming: true,
  185. inputType: "Foo",
  186. outputType: "Bar"
  187. ),
  188. ]
  189. )
  190. let request = makeCodeGenerationRequest(services: [service])
  191. let translator = IDLToStructuredSwiftTranslator()
  192. let structuredSwift = try translator.translate(
  193. codeGenerationRequest: request,
  194. accessLevel: .internal,
  195. accessLevelOnImports: false,
  196. client: true,
  197. server: true,
  198. grpcCoreModuleName: String("GRPCCore".reversed()),
  199. availability: .macOS15Aligned
  200. )
  201. let renderer = TextBasedRenderer.default
  202. let sourceFile = try renderer.render(structured: structuredSwift)
  203. let contents = sourceFile.contents
  204. XCTAssertFalse(contents.contains("GRPCCore"))
  205. }
  206. func testEmptyFileGeneration() throws {
  207. let expectedSwift =
  208. """
  209. /// Some really exciting license header 2023.
  210. // This file contained no services.
  211. """
  212. try self.assertIDLToStructuredSwiftTranslation(
  213. codeGenerationRequest: makeCodeGenerationRequest(
  214. services: [],
  215. dependencies: []
  216. ),
  217. expectedSwift: expectedSwift,
  218. accessLevel: .public,
  219. server: true
  220. )
  221. }
  222. private func assertIDLToStructuredSwiftTranslation(
  223. codeGenerationRequest: CodeGenerationRequest,
  224. expectedSwift: String,
  225. accessLevel: CodeGenerator.Config.AccessLevel,
  226. server: Bool = false,
  227. grpcCoreModuleName: String = "GRPCCore"
  228. ) throws {
  229. let translator = IDLToStructuredSwiftTranslator()
  230. let structuredSwift = try translator.translate(
  231. codeGenerationRequest: codeGenerationRequest,
  232. accessLevel: accessLevel,
  233. accessLevelOnImports: true,
  234. client: false,
  235. server: server,
  236. grpcCoreModuleName: grpcCoreModuleName,
  237. availability: .macOS15Aligned
  238. )
  239. let renderer = TextBasedRenderer.default
  240. let sourceFile = try renderer.render(structured: structuredSwift)
  241. let contents = sourceFile.contents
  242. try XCTAssertEqualWithDiff(contents, expectedSwift)
  243. }
  244. func testSameNameServicesNoNamespaceError() throws {
  245. let serviceA = ServiceDescriptor(
  246. documentation: "Documentation for AService",
  247. name: ServiceName(
  248. identifyingName: "AService",
  249. typeName: "AService",
  250. propertyName: "aService"
  251. ),
  252. methods: []
  253. )
  254. let codeGenerationRequest = makeCodeGenerationRequest(services: [serviceA, serviceA])
  255. let translator = IDLToStructuredSwiftTranslator()
  256. XCTAssertThrowsError(
  257. ofType: CodeGenError.self,
  258. try translator.translate(
  259. codeGenerationRequest: codeGenerationRequest,
  260. accessLevel: .public,
  261. accessLevelOnImports: true,
  262. client: true,
  263. server: true,
  264. grpcCoreModuleName: "GRPCCore",
  265. availability: .macOS15Aligned
  266. )
  267. ) {
  268. error in
  269. XCTAssertEqual(
  270. error as CodeGenError,
  271. CodeGenError(
  272. code: .nonUniqueServiceName,
  273. message: """
  274. Services must have unique descriptors. \
  275. AService is the descriptor of at least two different services.
  276. """
  277. )
  278. )
  279. }
  280. }
  281. func testSameDescriptorsServicesNoNamespaceError() throws {
  282. let serviceA = ServiceDescriptor(
  283. documentation: "Documentation for AService",
  284. name: ServiceName(
  285. identifyingName: "AService",
  286. typeName: "AService",
  287. propertyName: "aService"
  288. ),
  289. methods: []
  290. )
  291. let serviceB = ServiceDescriptor(
  292. documentation: "Documentation for BService",
  293. name: ServiceName(
  294. identifyingName: "AService",
  295. typeName: "AService",
  296. propertyName: "aService"
  297. ),
  298. methods: []
  299. )
  300. let codeGenerationRequest = makeCodeGenerationRequest(services: [serviceA, serviceB])
  301. let translator = IDLToStructuredSwiftTranslator()
  302. XCTAssertThrowsError(
  303. ofType: CodeGenError.self,
  304. try translator.translate(
  305. codeGenerationRequest: codeGenerationRequest,
  306. accessLevel: .public,
  307. accessLevelOnImports: true,
  308. client: true,
  309. server: true,
  310. grpcCoreModuleName: "GRPCCore",
  311. availability: .macOS15Aligned
  312. )
  313. ) {
  314. error in
  315. XCTAssertEqual(
  316. error as CodeGenError,
  317. CodeGenError(
  318. code: .nonUniqueServiceName,
  319. message: """
  320. Services must have unique descriptors. AService is the descriptor of at least two different services.
  321. """
  322. )
  323. )
  324. }
  325. }
  326. func testSameDescriptorsSameNamespaceError() throws {
  327. let serviceA = ServiceDescriptor(
  328. documentation: "Documentation for AService",
  329. name: ServiceName(
  330. identifyingName: "namespacea.AService",
  331. typeName: "NamespaceA_AService",
  332. propertyName: "namespacea_aService"
  333. ),
  334. methods: []
  335. )
  336. let codeGenerationRequest = makeCodeGenerationRequest(services: [serviceA, serviceA])
  337. let translator = IDLToStructuredSwiftTranslator()
  338. XCTAssertThrowsError(
  339. ofType: CodeGenError.self,
  340. try translator.translate(
  341. codeGenerationRequest: codeGenerationRequest,
  342. accessLevel: .public,
  343. accessLevelOnImports: true,
  344. client: true,
  345. server: true,
  346. grpcCoreModuleName: "GRPCCore",
  347. availability: .macOS15Aligned
  348. )
  349. ) {
  350. error in
  351. XCTAssertEqual(
  352. error as CodeGenError,
  353. CodeGenError(
  354. code: .nonUniqueServiceName,
  355. message: """
  356. Services must have unique descriptors. \
  357. namespacea.AService is the descriptor of at least two different services.
  358. """
  359. )
  360. )
  361. }
  362. }
  363. func testSameGeneratedNameServicesSameNamespaceError() throws {
  364. let serviceA = ServiceDescriptor(
  365. documentation: "/// Documentation for AService\n",
  366. name: ServiceName(
  367. identifyingName: "namespacea.AService",
  368. typeName: "NamespaceA_AService",
  369. propertyName: "namespacea_aService"
  370. ),
  371. methods: []
  372. )
  373. let serviceB = ServiceDescriptor(
  374. documentation: "/// Documentation for BService\n",
  375. name: ServiceName(
  376. identifyingName: "namespacea.BService",
  377. typeName: "NamespaceA_AService",
  378. propertyName: "namespacea_aService"
  379. ),
  380. methods: []
  381. )
  382. let codeGenerationRequest = makeCodeGenerationRequest(services: [serviceA, serviceB])
  383. let translator = IDLToStructuredSwiftTranslator()
  384. XCTAssertThrowsError(
  385. ofType: CodeGenError.self,
  386. try translator.translate(
  387. codeGenerationRequest: codeGenerationRequest,
  388. accessLevel: .internal,
  389. accessLevelOnImports: true,
  390. client: true,
  391. server: true,
  392. grpcCoreModuleName: "GRPCCore",
  393. availability: .macOS15Aligned
  394. )
  395. ) { error in
  396. XCTAssertEqual(
  397. error as CodeGenError,
  398. CodeGenError(
  399. code: .nonUniqueServiceName,
  400. message: """
  401. There must be a unique (namespace, service_name) pair for each service. \
  402. NamespaceA_AService is used as a <namespace>_<service_name> construction for multiple services.
  403. """
  404. )
  405. )
  406. }
  407. }
  408. func testSameBaseNameMethodsSameServiceError() throws {
  409. let methodA = MethodDescriptor(
  410. documentation: "Documentation for MethodA",
  411. name: MethodName(identifyingName: "MethodA", typeName: "MethodA", functionName: "methodA"),
  412. isInputStreaming: false,
  413. isOutputStreaming: false,
  414. inputType: "NamespaceA_ServiceARequest",
  415. outputType: "NamespaceA_ServiceAResponse"
  416. )
  417. let service = ServiceDescriptor(
  418. documentation: "Documentation for AService",
  419. name: ServiceName(
  420. identifyingName: "namespacea.AService",
  421. typeName: "NamespaceA_AService",
  422. propertyName: "namespacea_aService"
  423. ),
  424. methods: [methodA, methodA]
  425. )
  426. let codeGenerationRequest = makeCodeGenerationRequest(services: [service])
  427. let translator = IDLToStructuredSwiftTranslator()
  428. XCTAssertThrowsError(
  429. ofType: CodeGenError.self,
  430. try translator.translate(
  431. codeGenerationRequest: codeGenerationRequest,
  432. accessLevel: .public,
  433. accessLevelOnImports: true,
  434. client: true,
  435. server: true,
  436. grpcCoreModuleName: "GRPCCore",
  437. availability: .macOS15Aligned
  438. )
  439. ) { error in
  440. XCTAssertEqual(
  441. error as CodeGenError,
  442. CodeGenError(
  443. code: .nonUniqueMethodName,
  444. message: """
  445. Methods of a service must have unique base names. \
  446. MethodA is used as a base name for multiple methods of the namespacea.AService service.
  447. """
  448. )
  449. )
  450. }
  451. }
  452. func testSameGeneratedUpperCaseNameMethodsSameServiceError() throws {
  453. let methodA = MethodDescriptor(
  454. documentation: "Documentation for MethodA",
  455. name: MethodName(
  456. identifyingName: "MethodA",
  457. typeName: "MethodA",
  458. functionName: "methodA"
  459. ),
  460. isInputStreaming: false,
  461. isOutputStreaming: false,
  462. inputType: "NamespaceA_ServiceARequest",
  463. outputType: "NamespaceA_ServiceAResponse"
  464. )
  465. let methodB = MethodDescriptor(
  466. documentation: "Documentation for MethodA",
  467. name: MethodName(
  468. identifyingName: "MethodB",
  469. typeName: "MethodA",
  470. functionName: "methodA"
  471. ),
  472. isInputStreaming: false,
  473. isOutputStreaming: false,
  474. inputType: "NamespaceA_ServiceARequest",
  475. outputType: "NamespaceA_ServiceAResponse"
  476. )
  477. let service = ServiceDescriptor(
  478. documentation: "Documentation for AService",
  479. name: ServiceName(
  480. identifyingName: "namespacea.AService",
  481. typeName: "NamespaceA_AService",
  482. propertyName: "namespacea_AService"
  483. ),
  484. methods: [methodA, methodB]
  485. )
  486. let codeGenerationRequest = makeCodeGenerationRequest(services: [service])
  487. let translator = IDLToStructuredSwiftTranslator()
  488. XCTAssertThrowsError(
  489. ofType: CodeGenError.self,
  490. try translator.translate(
  491. codeGenerationRequest: codeGenerationRequest,
  492. accessLevel: .public,
  493. accessLevelOnImports: true,
  494. client: true,
  495. server: true,
  496. grpcCoreModuleName: "GRPCCore",
  497. availability: .macOS15Aligned
  498. )
  499. ) { error in
  500. XCTAssertEqual(
  501. error as CodeGenError,
  502. CodeGenError(
  503. code: .nonUniqueMethodName,
  504. message: """
  505. Methods of a service must have unique generated upper case names. \
  506. MethodA is used as a generated upper case name for multiple methods of the \
  507. namespacea.AService service.
  508. """
  509. )
  510. )
  511. }
  512. }
  513. func testSameLowerCaseNameMethodsSameServiceError() throws {
  514. let methodA = MethodDescriptor(
  515. documentation: "Documentation for MethodA",
  516. name: MethodName(identifyingName: "MethodA", typeName: "MethodA", functionName: "methodA"),
  517. isInputStreaming: false,
  518. isOutputStreaming: false,
  519. inputType: "NamespaceA_ServiceARequest",
  520. outputType: "NamespaceA_ServiceAResponse"
  521. )
  522. let methodB = MethodDescriptor(
  523. documentation: "Documentation for MethodA",
  524. name: MethodName(identifyingName: "MethodB", typeName: "MethodB", functionName: "methodA"),
  525. isInputStreaming: false,
  526. isOutputStreaming: false,
  527. inputType: "NamespaceA_ServiceARequest",
  528. outputType: "NamespaceA_ServiceAResponse"
  529. )
  530. let service = ServiceDescriptor(
  531. documentation: "Documentation for AService",
  532. name: ServiceName(
  533. identifyingName: "namespacea.AService",
  534. typeName: "NamespaceA_AService",
  535. propertyName: "namespacea_aService"
  536. ),
  537. methods: [methodA, methodB]
  538. )
  539. let codeGenerationRequest = makeCodeGenerationRequest(services: [service])
  540. let translator = IDLToStructuredSwiftTranslator()
  541. XCTAssertThrowsError(
  542. ofType: CodeGenError.self,
  543. try translator.translate(
  544. codeGenerationRequest: codeGenerationRequest,
  545. accessLevel: .public,
  546. accessLevelOnImports: true,
  547. client: true,
  548. server: true,
  549. grpcCoreModuleName: "GRPCCore",
  550. availability: .macOS15Aligned
  551. )
  552. ) {
  553. error in
  554. XCTAssertEqual(
  555. error as CodeGenError,
  556. CodeGenError(
  557. code: .nonUniqueMethodName,
  558. message: """
  559. Methods of a service must have unique lower case names. \
  560. methodA is used as a signature name for multiple methods of the \
  561. namespacea.AService service.
  562. """
  563. )
  564. )
  565. }
  566. }
  567. func testSameGeneratedNameNoNamespaceServiceAndNamespaceError() throws {
  568. let serviceA = ServiceDescriptor(
  569. documentation: "Documentation for SameName service with no namespace",
  570. name: ServiceName(
  571. identifyingName: "SameName",
  572. typeName: "SameName_BService",
  573. propertyName: "sameName"
  574. ),
  575. methods: []
  576. )
  577. let serviceB = ServiceDescriptor(
  578. documentation: "Documentation for BService",
  579. name: ServiceName(
  580. identifyingName: "sameName.BService",
  581. typeName: "SameName_BService",
  582. propertyName: "sameName"
  583. ),
  584. methods: []
  585. )
  586. let codeGenerationRequest = makeCodeGenerationRequest(services: [serviceA, serviceB])
  587. let translator = IDLToStructuredSwiftTranslator()
  588. XCTAssertThrowsError(
  589. ofType: CodeGenError.self,
  590. try translator.translate(
  591. codeGenerationRequest: codeGenerationRequest,
  592. accessLevel: .public,
  593. accessLevelOnImports: true,
  594. client: true,
  595. server: true,
  596. grpcCoreModuleName: "GRPCCore",
  597. availability: .macOS15Aligned
  598. )
  599. ) {
  600. error in
  601. XCTAssertEqual(
  602. error as CodeGenError,
  603. CodeGenError(
  604. code: .nonUniqueServiceName,
  605. message: """
  606. There must be a unique (namespace, service_name) pair for each service. \
  607. SameName_BService is used as a <namespace>_<service_name> construction for multiple services.
  608. """
  609. )
  610. )
  611. }
  612. }
  613. }
  614. #endif // os(macOS) || os(Linux)