ReflectionServiceUnitTests.swift 22 KB

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