ReflectionServiceUnitTests.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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. import Foundation
  17. import GRPC
  18. import GRPCReflectionService
  19. import SwiftProtobuf
  20. import XCTest
  21. @testable import GRPCReflectionService
  22. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  23. final class ReflectionServiceUnitTests: GRPCTestCase {
  24. /// Testing the fileDescriptorDataByFilename dictionary of the ReflectionServiceData object.
  25. func testFileDescriptorDataByFilename() throws {
  26. var protos = makeProtosWithDependencies()
  27. let registry = try ReflectionServiceData(fileDescriptors: protos)
  28. let registryFileDescriptorData = registry.fileDescriptorDataByFilename
  29. for (fileName, protoData) in registryFileDescriptorData {
  30. let serializedFiledescriptorData = protoData.serializedFileDescriptorProto
  31. let dependencyFileNames = protoData.dependencyFileNames
  32. guard let index = protos.firstIndex(where: { $0.name == fileName }) else {
  33. return XCTFail(
  34. """
  35. Could not find the file descriptor proto of \(fileName) \
  36. in the original file descriptor protos list.
  37. """
  38. )
  39. }
  40. let originalProto = protos[index]
  41. XCTAssertEqual(originalProto.name, fileName)
  42. XCTAssertEqual(try originalProto.serializedData(), serializedFiledescriptorData)
  43. XCTAssertEqual(originalProto.dependency, dependencyFileNames)
  44. protos.remove(at: index)
  45. }
  46. XCTAssert(protos.isEmpty)
  47. }
  48. /// Testing the serviceNames array of the ReflectionServiceData object.
  49. func testServiceNames() throws {
  50. let protos = makeProtosWithDependencies()
  51. let servicesNames = protos.flatMap { $0.qualifiedServiceNames }.sorted()
  52. let registry = try ReflectionServiceData(fileDescriptors: protos)
  53. let registryServices = registry.serviceNames.sorted()
  54. XCTAssertEqual(registryServices, servicesNames)
  55. }
  56. /// Testing the fileNameBySymbol dictionary of the ReflectionServiceData object.
  57. func testFileNameBySymbol() throws {
  58. let protos = makeProtosWithDependencies()
  59. let registry = try ReflectionServiceData(fileDescriptors: protos)
  60. let registryFileNameBySymbol = registry.fileNameBySymbol
  61. var symbolsCount = 0
  62. for proto in protos {
  63. let qualifiedSymbolNames = proto.qualifiedSymbolNames
  64. symbolsCount += qualifiedSymbolNames.count
  65. for qualifiedSymbolName in qualifiedSymbolNames {
  66. XCTAssertEqual(registryFileNameBySymbol[qualifiedSymbolName], proto.name)
  67. }
  68. }
  69. XCTAssertEqual(symbolsCount, registryFileNameBySymbol.count)
  70. }
  71. func testFileNameBySymbolDuplicatedSymbol() throws {
  72. var protos = makeProtosWithDependencies()
  73. protos[1].messageType.append(
  74. Google_Protobuf_DescriptorProto.with {
  75. $0.name = "inputMessage2"
  76. $0.field = [
  77. Google_Protobuf_FieldDescriptorProto.with {
  78. $0.name = "inputField"
  79. $0.type = .bool
  80. }
  81. ]
  82. }
  83. )
  84. XCTAssertThrowsError(
  85. try ReflectionServiceData(fileDescriptors: protos)
  86. ) { error in
  87. XCTAssertEqual(
  88. error as? GRPCStatus,
  89. GRPCStatus(
  90. code: .alreadyExists,
  91. message:
  92. """
  93. The packagebar2.inputMessage2 symbol from bar2.proto \
  94. already exists in bar2.proto.
  95. """
  96. )
  97. )
  98. }
  99. }
  100. // Testing the nameOfFileContainingSymbol method for different types of symbols.
  101. func testNameOfFileContainingSymbolEnum() throws {
  102. let protos = makeProtosWithDependencies()
  103. let registry = try ReflectionServiceData(fileDescriptors: protos)
  104. let nameOfFileContainingSymbolResult = registry.nameOfFileContainingSymbol(
  105. named: "packagebar2.enumType2"
  106. )
  107. XCTAssertEqual(try nameOfFileContainingSymbolResult.get(), "bar2.proto")
  108. }
  109. func testNameOfFileContainingSymbolMessage() throws {
  110. let protos = makeProtosWithDependencies()
  111. let registry = try ReflectionServiceData(fileDescriptors: protos)
  112. let nameOfFileContainingSymbolResult = registry.nameOfFileContainingSymbol(
  113. named: "packagebar1.inputMessage1"
  114. )
  115. XCTAssertEqual(try nameOfFileContainingSymbolResult.get(), "bar1.proto")
  116. }
  117. func testNameOfFileContainingSymbolService() throws {
  118. let protos = makeProtosWithDependencies()
  119. let registry = try ReflectionServiceData(fileDescriptors: protos)
  120. let nameOfFileContainingSymbolResult = registry.nameOfFileContainingSymbol(
  121. named: "packagebar3.service3"
  122. )
  123. XCTAssertEqual(try nameOfFileContainingSymbolResult.get(), "bar3.proto")
  124. }
  125. func testNameOfFileContainingSymbolMethod() throws {
  126. let protos = makeProtosWithDependencies()
  127. let registry = try ReflectionServiceData(fileDescriptors: protos)
  128. let nameOfFileContainingSymbolResult = registry.nameOfFileContainingSymbol(
  129. named: "packagebar4.service4.testMethod4"
  130. )
  131. XCTAssertEqual(try nameOfFileContainingSymbolResult.get(), "bar4.proto")
  132. }
  133. func testNameOfFileContainingSymbolNonExistentSymbol() throws {
  134. let protos = makeProtosWithDependencies()
  135. let registry = try ReflectionServiceData(fileDescriptors: protos)
  136. let nameOfFileContainingSymbolResult = registry.nameOfFileContainingSymbol(
  137. named: "packagebar2.enumType3"
  138. )
  139. XCTAssertThrowsGRPCStatus(try nameOfFileContainingSymbolResult.get()) {
  140. status in
  141. XCTAssertEqual(
  142. status,
  143. GRPCStatus(code: .notFound, message: "The provided symbol could not be found.")
  144. )
  145. }
  146. }
  147. // Testing the serializedFileDescriptorProto method in different cases.
  148. func testSerialisedFileDescriptorProtosForDependenciesOfFile() throws {
  149. var protos = makeProtosWithDependencies()
  150. let registry = try ReflectionServiceData(fileDescriptors: protos)
  151. let serializedFileDescriptorProtosResult =
  152. registry
  153. .serialisedFileDescriptorProtosForDependenciesOfFile(named: "bar1.proto")
  154. switch serializedFileDescriptorProtosResult {
  155. case .success(let serializedFileDescriptorProtos):
  156. let fileDescriptorProtos = try serializedFileDescriptorProtos.map {
  157. try Google_Protobuf_FileDescriptorProto(serializedBytes: $0)
  158. }
  159. // Tests that the functions returns all the transitive dependencies, with their services and
  160. // methods, together with the initial proto, as serialized data.
  161. XCTAssertEqual(fileDescriptorProtos.count, 4)
  162. for fileDescriptorProto in fileDescriptorProtos {
  163. guard let protoIndex = protos.firstIndex(of: fileDescriptorProto) else {
  164. return XCTFail(
  165. """
  166. Could not find the file descriptor proto of \(fileDescriptorProto.name) \
  167. in the original file descriptor protos list.
  168. """
  169. )
  170. }
  171. for service in fileDescriptorProto.service {
  172. guard let serviceIndex = protos[protoIndex].service.firstIndex(of: service) else {
  173. return XCTFail(
  174. """
  175. Could not find the \(service.name) in the service \
  176. list of the \(fileDescriptorProto.name) file descriptor proto.
  177. """
  178. )
  179. }
  180. let originalMethods = protos[protoIndex].service[serviceIndex].method
  181. for method in service.method {
  182. XCTAssert(originalMethods.contains(method))
  183. }
  184. for messageType in fileDescriptorProto.messageType {
  185. XCTAssert(protos[protoIndex].messageType.contains(messageType))
  186. }
  187. }
  188. protos.removeAll { $0 == fileDescriptorProto }
  189. }
  190. XCTAssert(protos.isEmpty)
  191. case .failure(let status):
  192. XCTFail(
  193. "Faild with GRPCStatus code: " + String(status.code.rawValue) + " and message: "
  194. + (status.message ?? "empty") + "."
  195. )
  196. }
  197. }
  198. func testSerialisedFileDescriptorProtosForDependenciesOfFileComplexDependencyGraph() throws {
  199. var protos = makeProtosWithComplexDependencies()
  200. let registry = try ReflectionServiceData(fileDescriptors: protos)
  201. let serializedFileDescriptorProtosResult =
  202. registry
  203. .serialisedFileDescriptorProtosForDependenciesOfFile(named: "foo0.proto")
  204. switch serializedFileDescriptorProtosResult {
  205. case .success(let serializedFileDescriptorProtos):
  206. let fileDescriptorProtos = try serializedFileDescriptorProtos.map {
  207. try Google_Protobuf_FileDescriptorProto(serializedBytes: $0)
  208. }
  209. // Tests that the functions returns all the tranzitive dependencies, with their services and
  210. // methods, together with the initial proto, as serialized data.
  211. XCTAssertEqual(fileDescriptorProtos.count, 21)
  212. for fileDescriptorProto in fileDescriptorProtos {
  213. guard let protoIndex = protos.firstIndex(of: fileDescriptorProto) else {
  214. return XCTFail(
  215. """
  216. Could not find the file descriptor proto of \(fileDescriptorProto.name) \
  217. in the original file descriptor protos list.
  218. """
  219. )
  220. }
  221. for service in fileDescriptorProto.service {
  222. guard let serviceIndex = protos[protoIndex].service.firstIndex(of: service) else {
  223. return XCTFail(
  224. """
  225. Could not find the \(service.name) in the service \
  226. list of the \(fileDescriptorProto.name) file descriptor proto.
  227. """
  228. )
  229. }
  230. let originalMethods = protos[protoIndex].service[serviceIndex].method
  231. for method in service.method {
  232. XCTAssert(originalMethods.contains(method))
  233. }
  234. for messageType in fileDescriptorProto.messageType {
  235. XCTAssert(protos[protoIndex].messageType.contains(messageType))
  236. }
  237. }
  238. protos.removeAll { $0 == fileDescriptorProto }
  239. }
  240. XCTAssert(protos.isEmpty)
  241. case .failure(let status):
  242. XCTFail(
  243. "Faild with GRPCStatus code: " + String(status.code.rawValue) + " and message: "
  244. + (status.message ?? "empty") + "."
  245. )
  246. }
  247. }
  248. func testSerialisedFileDescriptorProtosForDependenciesOfFileDependencyLoops() throws {
  249. var protos = makeProtosWithDependencies()
  250. // Making dependencies of the "bar1.proto" to depend on "bar1.proto".
  251. protos[1].dependency.append("bar1.proto")
  252. protos[2].dependency.append("bar1.proto")
  253. protos[3].dependency.append("bar1.proto")
  254. let registry = try ReflectionServiceData(fileDescriptors: protos)
  255. let serializedFileDescriptorProtosResult =
  256. registry
  257. .serialisedFileDescriptorProtosForDependenciesOfFile(named: "bar1.proto")
  258. switch serializedFileDescriptorProtosResult {
  259. case .success(let serializedFileDescriptorProtos):
  260. let fileDescriptorProtos = try serializedFileDescriptorProtos.map {
  261. try Google_Protobuf_FileDescriptorProto(serializedBytes: $0)
  262. }
  263. // Test that we get only 4 serialized File Descriptor Protos as response.
  264. XCTAssertEqual(fileDescriptorProtos.count, 4)
  265. for fileDescriptorProto in fileDescriptorProtos {
  266. guard let protoIndex = protos.firstIndex(of: fileDescriptorProto) else {
  267. return XCTFail(
  268. """
  269. Could not find the file descriptor proto of \(fileDescriptorProto.name) \
  270. in the original file descriptor protos list.
  271. """
  272. )
  273. }
  274. for service in fileDescriptorProto.service {
  275. guard let serviceIndex = protos[protoIndex].service.firstIndex(of: service) else {
  276. return XCTFail(
  277. """
  278. Could not find the \(service.name) in the service \
  279. list of the \(fileDescriptorProto.name) file descriptor proto.
  280. """
  281. )
  282. }
  283. let originalMethods = protos[protoIndex].service[serviceIndex].method
  284. for method in service.method {
  285. XCTAssert(originalMethods.contains(method))
  286. }
  287. for messageType in fileDescriptorProto.messageType {
  288. XCTAssert(protos[protoIndex].messageType.contains(messageType))
  289. }
  290. }
  291. protos.removeAll { $0 == fileDescriptorProto }
  292. }
  293. XCTAssert(protos.isEmpty)
  294. case .failure(let status):
  295. XCTFail(
  296. "Faild with GRPCStatus code: " + String(status.code.rawValue) + " and message: "
  297. + (status.message ?? "empty") + "."
  298. )
  299. }
  300. }
  301. func testSerialisedFileDescriptorProtosForDependenciesOfFileInvalidFile() throws {
  302. let protos = makeProtosWithDependencies()
  303. let registry = try ReflectionServiceData(fileDescriptors: protos)
  304. let serializedFileDescriptorProtosForDependenciesOfFileResult =
  305. registry.serialisedFileDescriptorProtosForDependenciesOfFile(named: "invalid.proto")
  306. XCTAssertThrowsGRPCStatus(try serializedFileDescriptorProtosForDependenciesOfFileResult.get()) {
  307. status in
  308. XCTAssertEqual(
  309. status,
  310. GRPCStatus(
  311. code: .notFound,
  312. message: "No reflection data for 'invalid.proto'."
  313. )
  314. )
  315. }
  316. }
  317. func testSerialisedFileDescriptorProtosForDependenciesOfFileDependencyNotProto() throws {
  318. var protos = makeProtosWithDependencies()
  319. protos[0].dependency.append("invalidDependency")
  320. let registry = try ReflectionServiceData(fileDescriptors: protos)
  321. let serializedFileDescriptorProtosForDependenciesOfFileResult =
  322. registry.serialisedFileDescriptorProtosForDependenciesOfFile(named: "bar1.proto")
  323. XCTAssertThrowsGRPCStatus(try serializedFileDescriptorProtosForDependenciesOfFileResult.get()) {
  324. status in
  325. XCTAssertEqual(
  326. status,
  327. GRPCStatus(
  328. code: .notFound,
  329. message:
  330. "No reflection data for 'invalidDependency' which is a dependency of 'bar1.proto'."
  331. )
  332. )
  333. }
  334. }
  335. // Testing the nameOfFileContainingExtension() method.
  336. func testNameOfFileContainingExtensions() throws {
  337. let protos = makeProtosWithDependencies()
  338. let registry = try ReflectionServiceData(fileDescriptors: protos)
  339. for proto in protos {
  340. for `extension` in proto.extension {
  341. let typeName = String(`extension`.extendee.drop(while: { $0 == "." }))
  342. let registryFileNameResult = registry.nameOfFileContainingExtension(
  343. extendeeName: typeName,
  344. fieldNumber: `extension`.number
  345. )
  346. XCTAssertEqual(try registryFileNameResult.get(), proto.name)
  347. }
  348. }
  349. }
  350. func testNameOfFileContainingExtensionsInvalidTypeName() throws {
  351. let protos = makeProtosWithDependencies()
  352. let registry = try ReflectionServiceData(fileDescriptors: protos)
  353. let registryFileNameResult = registry.nameOfFileContainingExtension(
  354. extendeeName: "InvalidType",
  355. fieldNumber: 2
  356. )
  357. XCTAssertThrowsGRPCStatus(try registryFileNameResult.get()) {
  358. status in
  359. XCTAssertEqual(
  360. status,
  361. GRPCStatus(code: .notFound, message: "The provided extension could not be found.")
  362. )
  363. }
  364. }
  365. func testNameOfFileContainingExtensionsInvalidFieldNumber() throws {
  366. let protos = makeProtosWithDependencies()
  367. let registry = try ReflectionServiceData(fileDescriptors: protos)
  368. let registryFileNameResult = registry.nameOfFileContainingExtension(
  369. extendeeName: protos[0].extension[0].extendee,
  370. fieldNumber: 9
  371. )
  372. XCTAssertThrowsGRPCStatus(try registryFileNameResult.get()) {
  373. status in
  374. XCTAssertEqual(
  375. status,
  376. GRPCStatus(code: .notFound, message: "The provided extension could not be found.")
  377. )
  378. }
  379. }
  380. func testNameOfFileContainingExtensionsDuplicatedExtensions() throws {
  381. var protos = makeProtosWithDependencies()
  382. protos[0].extension.append(
  383. .with {
  384. $0.extendee = ".packagebar1.inputMessage1"
  385. $0.number = 2
  386. }
  387. )
  388. XCTAssertThrowsError(
  389. try ReflectionServiceData(fileDescriptors: protos)
  390. ) { error in
  391. XCTAssertEqual(
  392. error as? GRPCStatus,
  393. GRPCStatus(
  394. code: .alreadyExists,
  395. message:
  396. """
  397. The extension of the packagebar1.inputMessage1 type with the field number equal to \
  398. 2 from \(protos[0].name) already exists in \(protos[0].name).
  399. """
  400. )
  401. )
  402. }
  403. }
  404. // Testing the extensionsFieldNumbersOfType() method.
  405. func testExtensionsFieldNumbersOfType() throws {
  406. var protos = makeProtosWithDependencies()
  407. protos[0].extension.append(
  408. .with {
  409. $0.extendee = ".packagebar1.inputMessage1"
  410. $0.number = 120
  411. }
  412. )
  413. let registry = try ReflectionServiceData(fileDescriptors: protos)
  414. let extensionsFieldNumbersOfTypeResult = registry.extensionsFieldNumbersOfType(
  415. named: "packagebar1.inputMessage1"
  416. )
  417. XCTAssertEqual(try extensionsFieldNumbersOfTypeResult.get(), [1, 2, 3, 4, 5, 120])
  418. }
  419. func testExtensionsFieldNumbersOfTypeNoExtensionsType() throws {
  420. var protos = makeProtosWithDependencies()
  421. protos[0].messageType.append(
  422. Google_Protobuf_DescriptorProto.with {
  423. $0.name = "noExtensionMessage"
  424. $0.field = [
  425. Google_Protobuf_FieldDescriptorProto.with {
  426. $0.name = "noExtensionField"
  427. $0.type = .bool
  428. }
  429. ]
  430. }
  431. )
  432. let registry = try ReflectionServiceData(fileDescriptors: protos)
  433. let extensionsFieldNumbersOfTypeResult = registry.extensionsFieldNumbersOfType(
  434. named: "packagebar1.noExtensionMessage"
  435. )
  436. XCTAssertEqual(try extensionsFieldNumbersOfTypeResult.get(), [])
  437. }
  438. func testExtensionsFieldNumbersOfTypeInvalidTypeName() throws {
  439. let protos = makeProtosWithDependencies()
  440. let registry = try ReflectionServiceData(fileDescriptors: protos)
  441. let extensionsFieldNumbersOfTypeResult = registry.extensionsFieldNumbersOfType(
  442. named: "packagebar1.invalidTypeMessage"
  443. )
  444. XCTAssertThrowsGRPCStatus(try extensionsFieldNumbersOfTypeResult.get()) {
  445. status in
  446. XCTAssertEqual(
  447. status,
  448. GRPCStatus(code: .invalidArgument, message: "The provided type is invalid.")
  449. )
  450. }
  451. }
  452. func testExtensionsFieldNumbersOfTypeExtensionsInDifferentProtoFiles() throws {
  453. var protos = makeProtosWithDependencies()
  454. protos[2].extension.append(
  455. .with {
  456. $0.extendee = ".packagebar1.inputMessage1"
  457. $0.number = 130
  458. }
  459. )
  460. let registry = try ReflectionServiceData(fileDescriptors: protos)
  461. let extensionsFieldNumbersOfTypeResult = registry.extensionsFieldNumbersOfType(
  462. named: "packagebar1.inputMessage1"
  463. )
  464. XCTAssertEqual(try extensionsFieldNumbersOfTypeResult.get(), [1, 2, 3, 4, 5, 130])
  465. }
  466. func testReadSerializedFileDescriptorProto() throws {
  467. let initialFileDescriptorProto = generateFileDescriptorProto(fileName: "test", suffix: "1")
  468. let data = try initialFileDescriptorProto.serializedData().base64EncodedData()
  469. let temporaryDirectory: String
  470. #if os(Linux)
  471. temporaryDirectory = "/tmp/"
  472. #else
  473. if #available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) {
  474. temporaryDirectory = FileManager.default.temporaryDirectory.path()
  475. } else {
  476. temporaryDirectory = "/tmp/"
  477. }
  478. #endif
  479. let filePath = "\(temporaryDirectory)test\(UUID()).grpc.reflection"
  480. FileManager.default.createFile(atPath: filePath, contents: data)
  481. defer {
  482. XCTAssertNoThrow(try FileManager.default.removeItem(atPath: filePath))
  483. }
  484. let reflectionServiceFileDescriptorProto =
  485. try ReflectionService.readSerializedFileDescriptorProto(atPath: filePath)
  486. XCTAssertEqual(reflectionServiceFileDescriptorProto, initialFileDescriptorProto)
  487. }
  488. func testReadSerializedFileDescriptorProtoInvalidFileContents() throws {
  489. let invalidData = "%%%%%££££".data(using: .utf8)
  490. let temporaryDirectory: String
  491. #if os(Linux)
  492. temporaryDirectory = "/tmp/"
  493. #else
  494. if #available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) {
  495. temporaryDirectory = FileManager.default.temporaryDirectory.path()
  496. } else {
  497. temporaryDirectory = "/tmp/"
  498. }
  499. #endif
  500. let filePath = "\(temporaryDirectory)test\(UUID()).grpc.reflection"
  501. FileManager.default.createFile(atPath: filePath, contents: invalidData)
  502. defer {
  503. XCTAssertNoThrow(try FileManager.default.removeItem(atPath: filePath))
  504. }
  505. XCTAssertThrowsGRPCStatus(
  506. try ReflectionService.readSerializedFileDescriptorProto(atPath: filePath)
  507. ) {
  508. status in
  509. XCTAssertEqual(
  510. status,
  511. GRPCStatus(
  512. code: .invalidArgument,
  513. message:
  514. """
  515. The \(filePath) file contents could not be transformed \
  516. into serialized data representing a file descriptor proto.
  517. """
  518. )
  519. )
  520. }
  521. }
  522. func testReadSerializedFileDescriptorProtos() throws {
  523. let initialFileDescriptorProtos = makeProtosWithDependencies()
  524. var filePaths: [String] = []
  525. for initialFileDescriptorProto in initialFileDescriptorProtos {
  526. let data = try initialFileDescriptorProto.serializedData()
  527. .base64EncodedData()
  528. let temporaryDirectory: String
  529. #if os(Linux)
  530. temporaryDirectory = "/tmp/"
  531. #else
  532. if #available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) {
  533. temporaryDirectory = FileManager.default.temporaryDirectory.path()
  534. } else {
  535. temporaryDirectory = "/tmp/"
  536. }
  537. #endif
  538. let filePath = "\(temporaryDirectory)test\(UUID()).grpc.reflection"
  539. FileManager.default.createFile(atPath: filePath, contents: data)
  540. filePaths.append(filePath)
  541. }
  542. defer {
  543. for filePath in filePaths {
  544. XCTAssertNoThrow(try FileManager.default.removeItem(atPath: filePath))
  545. }
  546. }
  547. let reflectionServiceFileDescriptorProtos =
  548. try ReflectionService.readSerializedFileDescriptorProtos(atPaths: filePaths)
  549. XCTAssertEqual(reflectionServiceFileDescriptorProtos, initialFileDescriptorProtos)
  550. }
  551. }