From c96771c1af64edb0d5701b9b4b6726a5531ca1fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20R=C3=B6nnqvist?= Date: Fri, 7 Jan 2022 17:47:03 -0800 Subject: [PATCH] Adapt tests to work better in Swift CI (#45) * Add utility to create temp directories in unit tests * Create new target for test utilities * Pass the temporary directory to ConvertAction * Re-enable one skipped test * Update new tests to use `createTemporaryDirectory` helper * Remove `createDirectoryForLastPathComponent` argument in test helper * Update test helper documentation * Prefer `FileManager.temporaryDirectory` property in ConvertAction * Move `Files` and `Folder` types into test utility target * Add additional safety checks when creating and removing temporary directories * Replace `TempFolder` test class with `createTempFolder` test function * Use XCTUnwrap instead of force unwrap in test helper * Also shadow `FileManager.temporaryDirectory` in tests * Add temp directory test helper variant with "named" argument This is clearer at the call site when only a single path component is specified. * Fix test helper syntax in disabled preview server test * Re-enable one file monitoring test --- Package.swift | 11 +- .../FilesAndFolders.swift} | 145 +++++++-------- .../XCTestCase+TemporaryDirectory.swift | 89 +++++++++ .../Actions/Convert/ConvertAction.swift | 11 +- .../ConvertAction+CommandInitialization.swift | 1 + .../Benchmark/OutputSizeTests.swift | 6 +- .../DocumentationConverterTests.swift | 4 +- .../Indexing/NavigatorIndexTests.swift | 63 ++----- .../Infrastructure/BundleDiscoveryTests.swift | 30 +-- .../DocumentationContext+RootPageTests.swift | 9 +- .../DocumentationContextTests.swift | 173 +++--------------- .../DocumentationCuratorTests.swift | 11 +- .../ExternalReferenceResolverTests.swift | 9 +- .../InheritIntroducedAvailabilityTests.swift | 15 +- .../Infrastructure/NodeTagsTests.swift | 4 +- .../SymbolGraph/SymbolGraphLoaderTests.swift | 21 +-- ...SymbolGraphRelationshipsBuilderTests.swift | 6 +- .../Infrastructure/SymbolReferenceTests.swift | 6 +- .../LinkDestinationSummaryTests.swift | 20 +- .../Model/LineHighlighterTests.swift | 35 +--- .../SemaToRenderNodeMultiLanguageTests.swift | 12 +- .../Model/SemaToRenderNodeTests.swift | 2 +- .../Rendering/DefaultAvailabilityTests.swift | 4 +- .../Rendering/PlistSymbolTests.swift | 9 +- .../Semantics/SymbolTests.swift | 5 +- .../ShadowFileManagerTemporaryDirectory.swift | 23 +++ Tests/SwiftDocCTests/Utility/LMDBTests.swift | 23 +-- .../XCTestCase+LoadingTestData.swift | 79 ++++++++ .../ConvertSubcommandTests.swift | 19 +- .../ArgumentParsing/ErrorMessageTests.swift | 12 +- .../PreviewSubcommandTests.swift | 26 +-- .../ConvertActionIndexerTests.swift | 4 +- .../ConvertActionStaticHostableTests.swift | 16 +- .../ConvertActionTests.swift | 144 ++++++++------- .../DirectoryMonitorTests.swift | 24 +-- .../FolderStructure.swift | 9 +- .../FolderStructureTests.swift | 20 +- .../HTMLTemplateDirectory.swift | 1 + .../IndexActionTests.swift | 14 +- .../OutOfProcessReferenceResolverTests.swift | 37 +--- .../PreviewActionIntegrationTests.swift | 61 +++--- .../PreviewHTTPHandlerTests.swift | 11 +- .../PreviewServer/PreviewServerTests.swift | 34 ++-- .../DefaultRequestHandlerTests.swift | 11 +- .../FileRequestHandlerTests.swift | 54 +++--- .../SemanticAnalyzerTests.swift | 7 +- .../ShadowFileManagerTemporaryDirectory.swift | 23 +++ .../StaticHostableTransformerTests.swift | 48 ++--- .../TempFolderTests.swift | 46 ----- ...TransformForStaticHostingActionTests.swift | 35 ++-- .../Utility/FileTests.swift | 1 + .../Utility/TestFileSystem.swift | 2 +- .../Utility/TestFileSystemTests.swift | 9 +- 53 files changed, 669 insertions(+), 825 deletions(-) rename Sources/{SwiftDocC/Utility/DataStructures/File.swift => SwiftDocCTestUtilities/FilesAndFolders.swift} (64%) create mode 100644 Sources/SwiftDocCTestUtilities/XCTestCase+TemporaryDirectory.swift create mode 100644 Tests/SwiftDocCTests/ShadowFileManagerTemporaryDirectory.swift create mode 100644 Tests/SwiftDocCTests/XCTestCase+LoadingTestData.swift create mode 100644 Tests/SwiftDocCUtilitiesTests/ShadowFileManagerTemporaryDirectory.swift delete mode 100644 Tests/SwiftDocCUtilitiesTests/TempFolderTests.swift diff --git a/Package.swift b/Package.swift index 5f944e1150..770d4c8f9c 100644 --- a/Package.swift +++ b/Package.swift @@ -44,7 +44,10 @@ let package = Package( ]), .testTarget( name: "SwiftDocCTests", - dependencies: ["SwiftDocC"], + dependencies: [ + "SwiftDocC", + "SwiftDocCTestUtilities", + ], resources: [ .copy("Test Resources"), .copy("Test Bundles"), @@ -66,11 +69,17 @@ let package = Package( dependencies: [ "SwiftDocCUtilities", "SwiftDocC", + "SwiftDocCTestUtilities", ], resources: [ .copy("Test Resources"), .copy("Test Bundles"), ]), + + // Test utility library + .target( + name: "SwiftDocCTestUtilities", + dependencies: []), // Command-line tool .executableTarget( diff --git a/Sources/SwiftDocC/Utility/DataStructures/File.swift b/Sources/SwiftDocCTestUtilities/FilesAndFolders.swift similarity index 64% rename from Sources/SwiftDocC/Utility/DataStructures/File.swift rename to Sources/SwiftDocCTestUtilities/FilesAndFolders.swift index a4a67dee08..7656975393 100644 --- a/Sources/SwiftDocC/Utility/DataStructures/File.swift +++ b/Sources/SwiftDocCTestUtilities/FilesAndFolders.swift @@ -9,6 +9,7 @@ */ import Foundation +import XCTest /* This file contains API for working with folder hierarchies, and is extensible to allow for testing @@ -16,7 +17,7 @@ import Foundation */ /// An abstract representation of a file (or folder). -protocol File { +public protocol File { /// The name of the file. var name: String { get } @@ -24,7 +25,7 @@ protocol File { func write(to url: URL) throws } -extension File { +public extension File { /// Writes the file inside of a folder and returns the URL that it was written to. @discardableResult func write(inside url: URL) throws -> URL { @@ -35,12 +36,12 @@ extension File { } /// An item which provides data. -protocol DataRepresentable { +public protocol DataRepresentable { func data() throws -> Data } /// `DataRepresentable` can automatically write itself to disk via `Data.write(to:)` -extension DataRepresentable { +public extension DataRepresentable { func write(to url: URL) throws { try data().write(to: url) } @@ -49,17 +50,22 @@ extension DataRepresentable { // MARK: - /// An abstract representation of a folder, containing some files or folders. -struct Folder: File { - let name: String +public struct Folder: File { + public init(name: String, content: [File]) { + self.name = name + self.content = content + } + + public let name: String /// The files and sub folders that this folder contains. - let content: [File] + public let content: [File] - func appendingFile(_ newFile: File) -> Folder { + public func appendingFile(_ newFile: File) -> Folder { return Folder(name: name, content: content + [newFile]) } - func write(to url: URL) throws { + public func write(to url: URL) throws { try FileManager.default.createDirectory(at: url, withIntermediateDirectories: false, attributes: nil) for file in content { try file.write(inside: url) @@ -69,7 +75,7 @@ struct Folder: File { extension Folder { /// Returns a flat list of a folder's recursive listing for testing purposes. - var recursiveContent: [File] { + public var recursiveContent: [File] { var result = content for file in content { if let content = (file as? Folder)?.recursiveContent { @@ -81,13 +87,13 @@ extension Folder { } /// A representation of an Info.plist file. -struct InfoPlist: File, DataRepresentable { - let name = "Info.plist" +public struct InfoPlist: File, DataRepresentable { + public let name = "Info.plist" /// The information that the Into.plist file contains. - let content: Content + public let content: Content - init(displayName: String, identifier: String, versionString: String = "1.0", developmentRegion: String = "en") { + public init(displayName: String, identifier: String, versionString: String = "1.0", developmentRegion: String = "en") { self.content = Content( displayName: displayName, identifier: identifier, @@ -96,11 +102,11 @@ struct InfoPlist: File, DataRepresentable { ) } - struct Content: Codable, Equatable { - let displayName: String - let identifier: String - let versionString: String - let developmentRegion: String + public struct Content: Codable, Equatable { + public let displayName: String + public let identifier: String + public let versionString: String + public let developmentRegion: String fileprivate init(displayName: String, identifier: String, versionString: String, developmentRegion: String) { self.displayName = displayName @@ -117,7 +123,7 @@ struct InfoPlist: File, DataRepresentable { } } - func data() throws -> Data { + public func data() throws -> Data { // TODO: Replace this with PropertListEncoder (see below) when it's available in swift-corelibs-foundation // https://github.com/apple/swift-corelibs-foundation/commit/d2d72f88d93f7645b94c21af88a7c9f69c979e4f let infoPlist = [ @@ -136,74 +142,85 @@ struct InfoPlist: File, DataRepresentable { } /// A representation of a text file with some UTF-8 content. -struct TextFile: File, DataRepresentable { - let name: String +public struct TextFile: File, DataRepresentable { + public init(name: String, utf8Content: String) { + self.name = name + self.utf8Content = utf8Content + } + + public let name: String /// The UTF8 content of the file. - let utf8Content: String + public let utf8Content: String - func data() throws -> Data { + public func data() throws -> Data { return utf8Content.data(using: .utf8)! } } /// A representation of a text file with some UTF-8 content. -struct JSONFile: File, DataRepresentable { - let name: String +public struct JSONFile: File, DataRepresentable { + public init(name: String, content: Content) { + self.name = name + self.content = content + } + + public let name: String /// The UTF8 content of the file. - let content: Content + public let content: Content - func data() throws -> Data { + public func data() throws -> Data { return try JSONEncoder().encode(content) } } /// A copy of another file on disk somewhere. -struct CopyOfFile: File, DataRepresentable { - enum Error: DescribedError { +public struct CopyOfFile: File, DataRepresentable { + enum Error: LocalizedError { case notAFile(URL) var errorDescription: String { switch self { - case .notAFile(let url): return "Original url is not a file: \(url.path.singleQuoted)" + case .notAFile(let url): return "Original url is not a file: '\(url.path)'" } } } /// The original file. - let original: URL - let name: String + public let original: URL + public let name: String - init(original: URL, newName: String? = nil) { + public init(original: URL, newName: String? = nil) { self.original = original self.name = newName ?? original.lastPathComponent } - func data() throws -> Data { + public func data() throws -> Data { // Note that `CopyOfFile` always reads a file from disk and so it's okay // to use `FileManager.default` directly here instead of `FileManagerProtocol`. - guard !FileManager.default.directoryExists(atPath: original.path) else { throw Error.notAFile(original) } + var isDirectory: ObjCBool = false + guard FileManager.default.fileExists(atPath: original.path, isDirectory: &isDirectory), !isDirectory.boolValue else { throw Error.notAFile(original) } return try Data(contentsOf: original) } - func write(to url: URL) throws { + public func write(to url: URL) throws { try FileManager.default.copyItem(at: original, to: url) } } -struct CopyOfFolder: File { +public struct CopyOfFolder: File { /// The original file. let original: URL - let name: String + public let name: String let shouldCopyFile: (URL) -> Bool - init(original: URL, newName: String? = nil, filter shouldCopyFile: @escaping (URL) -> Bool = { _ in true }) { + public init(original: URL, newName: String? = nil, filter shouldCopyFile: @escaping (URL) -> Bool = { _ in true }) { self.original = original self.name = newName ?? original.lastPathComponent self.shouldCopyFile = shouldCopyFile } - func write(to url: URL) throws { + public func write(to url: URL) throws { try FileManager.default.createDirectory(at: url, withIntermediateDirectories: false, attributes: nil) for filePath in try FileManager.default.contentsOfDirectory(atPath: original.path) { // `contentsOfDirectory(atPath)` includes hidden files, skipHiddenFiles option doesn't help on Linux. @@ -217,46 +234,30 @@ struct CopyOfFolder: File { } /// A file backed by `Data`. -struct DataFile: File, DataRepresentable { - var name: String +public struct DataFile: File, DataRepresentable { + public var name: String var _data: Data - init(name: String, data: Data) { + public init(name: String, data: Data) { self.name = name self._data = data } - func data() throws -> Data { + public func data() throws -> Data { return _data } } -/// A temporary folder which can write files to a temporary location on disk and -/// will delete itself when its instance is released from memory. -class TempFolder: File { - let name: String - let url: URL - - /// The files and sub folders that this folder contains. - let content: [File] - - func write(to url: URL) throws { - try FileManager.default.createDirectory(at: url, withIntermediateDirectories: false, attributes: nil) - for file in content { - try file.write(inside: url) - } - } - - init(content: [File]) throws { - self.content = content - - url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - name = url.absoluteString - - try write(to: url) - } - - deinit { - try? FileManager.default.removeItem(at: url) +extension XCTestCase { + /// Creates a ``Folder`` and writes its content to a temporary location on disk. + /// + /// - Parameters: + /// - content: The files and subfolders to write to a temporary location + /// - Returns: The temporary location where the temporary folder was written. + public func createTempFolder(content: [File]) throws -> URL { + let temporaryDirectory = try createTemporaryDirectory().appendingPathComponent("TempDirectory-\(ProcessInfo.processInfo.globallyUniqueString)") + let folder = Folder(name: temporaryDirectory.lastPathComponent, content: content) + try folder.write(to: temporaryDirectory) + return temporaryDirectory } } diff --git a/Sources/SwiftDocCTestUtilities/XCTestCase+TemporaryDirectory.swift b/Sources/SwiftDocCTestUtilities/XCTestCase+TemporaryDirectory.swift new file mode 100644 index 0000000000..2389e18798 --- /dev/null +++ b/Sources/SwiftDocCTestUtilities/XCTestCase+TemporaryDirectory.swift @@ -0,0 +1,89 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation +import XCTest + +// These helpers methods exist to put temp files for different test executions in different locations when running in Swift CI. + +extension FileManager { + + @available(*, deprecated, message: "Use `createTemporaryDirectory` instead in unit tests to avoid referencing a shared location in Swift CI.") + var temporaryDirectory: URL { + XCTFail("Use `createTemporaryDirectory` instead in unit tests to avoid referencing a shared location in Swift CI.") + return URL(fileURLWithPath: Foundation.NSTemporaryDirectory()) + } +} + +public extension XCTestCase { + + @available(*, deprecated, message: "Use `createTemporaryDirectory` instead in unit tests to avoid referencing a shared location in Swift CI.") + func NSTemporaryDirectory() -> String { + XCTFail("Use `createTemporaryDirectory` instead in unit tests to avoid referencing a shared location in Swift CI.") + return Foundation.NSTemporaryDirectory() + } + + /// Creates a new temporary directory and returns the URL of that directory. + /// + /// After the current test method has returned the temporary directory is automatically removed. + /// + /// - Parameters: + /// - pathComponents: The name of the temporary directory. + /// - fileManager: The file manager that will create the directory. + /// - Returns: The URL of the newly created directory. + func createTemporaryDirectory(named: String, fileManager: FileManager = .default) throws -> URL { + try createTemporaryDirectory(pathComponents: named) + } + + /// Creates a new temporary directory and returns the URL of that directory. + /// + /// After the current test method has returned the temporary directory is automatically removed. + /// + /// - Parameters: + /// - pathComponents: Additional path components to add to the temporary URL. + /// - fileManager: The file manager that will create the directory. + /// - Returns: The URL of the newly created directory. + func createTemporaryDirectory(pathComponents: String..., fileManager: FileManager = .default) throws -> URL { + let bundleParentDir = Bundle(for: Self.self).bundleURL.deletingLastPathComponent() + let baseURL = bundleParentDir.appendingPathComponent(name.replacingWhitespaceAndPunctuation(with: "-")) + + var tempURL = baseURL.appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) + for component in pathComponents { + tempURL.appendPathComponent(component) + } + tempURL.standardize() + + addTeardownBlock { + do { + if fileManager.fileExists(atPath: baseURL.path) { + try fileManager.removeItem(at: baseURL) + } + } catch { + XCTFail("Failed to remove temporary directory: '\(error)'") + } + } + + if !fileManager.fileExists(atPath: bundleParentDir.path) { + // Create the base URL directory without intermediate directories so that an error is raised if the parent directory doesn't exist. + try fileManager.createDirectory(at: baseURL, withIntermediateDirectories: false, attributes: nil) + } + + try fileManager.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) + + return tempURL + } +} + +private extension String { + func replacingWhitespaceAndPunctuation(with separator: String) -> String { + let charactersToStrip = CharacterSet.whitespaces.union(.punctuationCharacters) + return components(separatedBy: charactersToStrip).filter({ !$0.isEmpty }).joined(separator: separator) + } +} diff --git a/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift b/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift index 72f973b3a0..730d1fe502 100644 --- a/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift +++ b/Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift @@ -59,6 +59,7 @@ public struct ConvertAction: Action, RecreatingContext { private var currentDataProvider: DocumentationWorkspaceDataProvider? private var injectedDataProvider: DocumentationWorkspaceDataProvider? private var fileManager: FileManagerProtocol + private let temporaryDirectory: URL public var setupContext: ((inout DocumentationContext) -> Void)? { didSet { @@ -86,6 +87,7 @@ public struct ConvertAction: Action, RecreatingContext { context: DocumentationContext? = nil, dataProvider: DocumentationWorkspaceDataProvider? = nil, fileManager: FileManagerProtocol = FileManager.default, + temporaryDirectory: URL, documentationCoverageOptions: DocumentationCoverageOptions = .noCoverage, bundleDiscoveryOptions: BundleDiscoveryOptions = .init(), diagnosticLevel: String? = nil, @@ -107,6 +109,7 @@ public struct ConvertAction: Action, RecreatingContext { self.workspace = workspace self.injectedDataProvider = dataProvider self.fileManager = fileManager + self.temporaryDirectory = temporaryDirectory self.documentationCoverageOptions = documentationCoverageOptions self.transformForStaticHosting = transformForStaticHosting self.hostingBasePath = hostingBasePath @@ -200,7 +203,8 @@ public struct ConvertAction: Action, RecreatingContext { inheritDocs: Bool = false, experimentalEnableCustomTemplates: Bool = false, transformForStaticHosting: Bool, - hostingBasePath: String? + hostingBasePath: String?, + temporaryDirectory: URL ) throws { // Note: This public initializer exists separately from the above internal one // because the FileManagerProtocol type we use to enable mocking in tests @@ -222,6 +226,7 @@ public struct ConvertAction: Action, RecreatingContext { context: context, dataProvider: dataProvider, fileManager: FileManager.default, + temporaryDirectory: temporaryDirectory, documentationCoverageOptions: documentationCoverageOptions, bundleDiscoveryOptions: bundleDiscoveryOptions, diagnosticLevel: diagnosticLevel, @@ -409,9 +414,7 @@ public struct ConvertAction: Action, RecreatingContext { } func createTempFolder(with templateURL: URL?) throws -> URL { - - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()) - .appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) + let targetURL = temporaryDirectory.appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) if let templateURL = templateURL { // If a template directory has been provided, create the temporary build folder with diff --git a/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift b/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift index 1d3357a485..4b918e0089 100644 --- a/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift +++ b/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift @@ -72,6 +72,7 @@ extension ConvertAction { emitDigest: convert.emitDigest, currentPlatforms: parsedPlatforms, buildIndex: convert.index, + temporaryDirectory: FileManager.default.temporaryDirectory, documentationCoverageOptions: DocumentationCoverageOptions( from: convert.experimentalDocumentationCoverageOptions ), diff --git a/Tests/SwiftDocCTests/Benchmark/OutputSizeTests.swift b/Tests/SwiftDocCTests/Benchmark/OutputSizeTests.swift index c513b3c452..bc2a8d94a8 100644 --- a/Tests/SwiftDocCTests/Benchmark/OutputSizeTests.swift +++ b/Tests/SwiftDocCTests/Benchmark/OutputSizeTests.swift @@ -14,11 +14,7 @@ import XCTest class OutputSizeTests: XCTestCase { func testOutputSize() throws { // Create a faux output folder - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - let writeURL = tempURL.appendingPathComponent(NodeURLGenerator.Path.dataFolderName) - - try FileManager.default.createDirectory(at: writeURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let writeURL = try createTemporaryDirectory(named: "data") // Write a 2MB file let data = Data(repeating: 1, count: 2 * 1024 * 1024) diff --git a/Tests/SwiftDocCTests/Converter/DocumentationConverterTests.swift b/Tests/SwiftDocCTests/Converter/DocumentationConverterTests.swift index 7669f6985a..e68fead2fe 100644 --- a/Tests/SwiftDocCTests/Converter/DocumentationConverterTests.swift +++ b/Tests/SwiftDocCTests/Converter/DocumentationConverterTests.swift @@ -26,9 +26,7 @@ class DocumentationConverterTests: XCTestCase { } func testThrowsErrorOnConvertingNoBundles() throws { - let rootURL = FileManager.default.temporaryDirectory.appendingPathComponent(#function, isDirectory: true) - try FileManager.default.createDirectory(at: rootURL, withIntermediateDirectories: false) - defer { try? FileManager.default.removeItem(at: rootURL) } + let rootURL = try createTemporaryDirectory() let dataProvider = try LocalFileSystemDataProvider(rootURL: rootURL) let workspace = DocumentationWorkspace() diff --git a/Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift b/Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift index fdfd8d6800..994c3c2f62 100644 --- a/Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift +++ b/Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift @@ -165,11 +165,7 @@ Root } func testNavigationTreeDumpAndRead() throws { - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: targetURL) - } + let targetURL = try createTemporaryDirectory() let indexURL = targetURL.appendingPathComponent("nav.index") let root = generateSmallTree() @@ -219,11 +215,7 @@ Root func testNavigationTreeLargeDumpAndRead() throws { #if os(OSX) - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: targetURL) - } + let targetURL = try createTemporaryDirectory() let indexURL = targetURL.appendingPathComponent("nav.index") let root = generateLargeTree() let original = NavigatorTree(root: root) @@ -235,15 +227,8 @@ Root #endif } - // This test has been disabled because of frequent failures in Swift CI. - // - // rdar://85055022 tracks updating this test to remove any flakiness. - func disabled_testNavigationTreeLargeDumpAndReadAsync() throws { - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: targetURL) - } + func testNavigationTreeLargeDumpAndReadAsync() throws { + let targetURL = try createTemporaryDirectory() let indexURL = targetURL.appendingPathComponent("nav.index") let root = generateLargeTree() @@ -284,11 +269,7 @@ Root } func testNavigatorIndexGenerationEmpty() throws { - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: targetURL) - } + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier) builder.setup() @@ -303,11 +284,7 @@ Root } func testNavigatorIndexGenerationOneNode() throws { - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: targetURL) - } + let targetURL = try createTemporaryDirectory() let indexURL = targetURL.appendingPathComponent("nav.index") let original = NavigatorTree(root: NavigatorTree.rootNode(bundleIdentifier: NavigatorIndex.UnknownBundleIdentifier)) @@ -337,11 +314,7 @@ Root let renderNode = try RenderNode.decode(fromJSON: Data(contentsOf: operatorURL)) - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: targetURL) - } + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier) builder.setup() @@ -359,7 +332,7 @@ Root // Create an index 10 times to ensure we have not undeterministic behavior across builds for _ in 0..<10 { - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true) builder.setup() @@ -405,7 +378,7 @@ Root let jsonFile = Bundle.module.url(forResource: "Variant-render-node", withExtension: "json", subdirectory: "Test Resources")! let jsonData = try Data(contentsOf: jsonFile) - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true, groupByLanguage: true) builder.setup() @@ -441,7 +414,7 @@ Root // Create an index 10 times to ensure we have not undeterministic behavior across builds for _ in 0..<10 { - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true, usePageTitle: true) builder.setup() @@ -490,7 +463,7 @@ Root // Create an index 10 times to ensure we have not undeterministic behavior across builds for _ in 0..<10 { - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true, writePathsOnDisk: false) builder.setup() @@ -532,7 +505,6 @@ Root assertUniqueIDs(node: navigatorIndex.navigatorTree.root) results.insert(navigatorIndex.navigatorTree.root.dumpTree()) - try FileManager.default.removeItem(at: targetURL) } XCTAssertEqual(results.count, 1) @@ -544,7 +516,7 @@ Root let renderContext = RenderContext(documentationContext: context, bundle: bundle) let converter = DocumentationContextConverter(bundle: bundle, context: context, renderContext: renderContext) - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true, groupByLanguage: true) builder.setup() @@ -594,7 +566,7 @@ Root // Create an index 10 times to ensure we have no undeterministic behavior across builds for _ in 0..<10 { - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true) builder.setup() @@ -654,7 +626,7 @@ Root let renderContext = RenderContext(documentationContext: context, bundle: bundle) let converter = DocumentationContextConverter(bundle: bundle, context: context, renderContext: renderContext) - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true) builder.setup() @@ -751,7 +723,7 @@ Root let renderContext = RenderContext(documentationContext: context, bundle: bundle) let converter = DocumentationContextConverter(bundle: bundle, context: context, renderContext: renderContext) - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true) builder.setup() @@ -1007,8 +979,7 @@ Root XCTAssertEqual(availabilityIndex.versions(for: .iOS)?.count, 4) XCTAssertEqual(availabilityIndex.versions(for: .macOS)?.count, 1) - let targetFolder = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: targetFolder, withIntermediateDirectories: true) + let targetFolder = try createTemporaryDirectory() let targetURL = targetFolder.appendingPathComponent("availability.index") let jsonEncoder = JSONEncoder() let data = try jsonEncoder.encode(availabilityIndex) @@ -1161,7 +1132,7 @@ Root let (bundle, context) = try testBundleAndContext(named: "TestBundle") let converter = DocumentationNodeConverter(bundle: bundle, context: context) - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: "org.swift.docc.test", sortRootChildrenByName: true) builder.setup() diff --git a/Tests/SwiftDocCTests/Infrastructure/BundleDiscoveryTests.swift b/Tests/SwiftDocCTests/Infrastructure/BundleDiscoveryTests.swift index 09cb0e8ced..9520c59775 100644 --- a/Tests/SwiftDocCTests/Infrastructure/BundleDiscoveryTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/BundleDiscoveryTests.swift @@ -10,6 +10,7 @@ import XCTest @testable import SwiftDocC +import SwiftDocCTestUtilities class BundleDiscoveryTests: XCTestCase { @@ -20,8 +21,7 @@ class BundleDiscoveryTests: XCTestCase { .filter { !$0.pathComponents.dropFirst(testBundleLocation.pathComponents.count).contains(where: { $0.hasPrefix(".") }) } func testFirstBundle() throws { - let url = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString)) - try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil) + let url = try createTemporaryDirectory() // Create 3 minimal doc bundles for i in 1 ... 3 { let nestedBundle = Folder(name: "TestBundle\(i).docc", content: [ @@ -38,8 +38,6 @@ class BundleDiscoveryTests: XCTestCase { ]) _ = try nestedBundle.write(inside: url) } - - defer { try? FileManager.default.removeItem(at: url) } let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) @@ -74,9 +72,7 @@ class BundleDiscoveryTests: XCTestCase { ]), ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let workspaceURL = try workspace.write(inside: tempURL) @@ -111,9 +107,7 @@ class BundleDiscoveryTests: XCTestCase { func testBundleFormat() throws { func parsedBundle(from folder: File) throws -> DocumentationBundle? { - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let workspaceURL = try folder.write(inside: tempURL) let dataProvider = try LocalFileSystemDataProvider(rootURL: workspaceURL) @@ -209,9 +203,7 @@ class BundleDiscoveryTests: XCTestCase { CopyOfFolder(original: testBundleLocation, newName: "Not a doc bundle", filter: { DocumentationBundleFileTypes.isSymbolGraphFile($0) }), ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let workspaceURL = try workspace.write(inside: tempURL) let dataProvider = try LocalFileSystemDataProvider(rootURL: workspaceURL) @@ -255,9 +247,7 @@ class BundleDiscoveryTests: XCTestCase { XCTAssertFalse(workspace.recursiveContent.contains(where: { $0.name == "Info.plist" }), "This bundle shouldn't contain an Info.plist file") - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let workspaceURL = try workspace.write(inside: tempURL) let dataProvider = try LocalFileSystemDataProvider(rootURL: workspaceURL) @@ -287,9 +277,7 @@ class BundleDiscoveryTests: XCTestCase { CopyOfFolder(original: testBundleLocation), ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let workspaceURL = try workspace.write(inside: tempURL) let dataProvider = try LocalFileSystemDataProvider(rootURL: workspaceURL) @@ -319,9 +307,7 @@ class BundleDiscoveryTests: XCTestCase { ] ) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let workspaceURL = try workspace.write(inside: tempURL) let dataProvider = try LocalFileSystemDataProvider(rootURL: workspaceURL) diff --git a/Tests/SwiftDocCTests/Infrastructure/DocumentationContext+RootPageTests.swift b/Tests/SwiftDocCTests/Infrastructure/DocumentationContext+RootPageTests.swift index 47b739658c..71961a724d 100644 --- a/Tests/SwiftDocCTests/Infrastructure/DocumentationContext+RootPageTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/DocumentationContext+RootPageTests.swift @@ -11,10 +11,11 @@ import XCTest import SymbolKit @testable import SwiftDocC +import SwiftDocCTestUtilities class DocumentationContext_RootPageTests: XCTestCase { func testNoSGFBundle() throws { - let tempFolder = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ Folder(name: "no-sgf-test.docc", content: [ // Root page for the collection TextFile(name: "ReleaseNotes.md", utf8Content: """ @@ -41,7 +42,7 @@ class DocumentationContext_RootPageTests: XCTestCase { // Parse this test content let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let dataProvider = try LocalFileSystemDataProvider(rootURL: tempFolder.url.appendingPathComponent("no-sgf-test.docc")) + let dataProvider = try LocalFileSystemDataProvider(rootURL: tempFolderURL.appendingPathComponent("no-sgf-test.docc")) try workspace.registerProvider(dataProvider) // Verify all articles were loaded in the context @@ -56,7 +57,7 @@ class DocumentationContext_RootPageTests: XCTestCase { } func testWarnForSidecarRootPage() throws { - let tempFolder = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ Folder(name: "no-sgf-test.docc", content: [ // Root page for the collection TextFile(name: "ReleaseNotes.md", utf8Content: """ @@ -83,7 +84,7 @@ class DocumentationContext_RootPageTests: XCTestCase { // Parse this test content let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let dataProvider = try LocalFileSystemDataProvider(rootURL: tempFolder.url.appendingPathComponent("no-sgf-test.docc")) + let dataProvider = try LocalFileSystemDataProvider(rootURL: tempFolderURL.appendingPathComponent("no-sgf-test.docc")) try workspace.registerProvider(dataProvider) // Verify that we emit a warning when trying to make a symbol a root page diff --git a/Tests/SwiftDocCTests/Infrastructure/DocumentationContextTests.swift b/Tests/SwiftDocCTests/Infrastructure/DocumentationContextTests.swift index 45af8d983a..4f5d366c7b 100644 --- a/Tests/SwiftDocCTests/Infrastructure/DocumentationContextTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/DocumentationContextTests.swift @@ -12,6 +12,7 @@ import XCTest import SymbolKit @testable import SwiftDocC import Markdown +import SwiftDocCTestUtilities func diffDescription(lhs: String, rhs: String) -> String { let leftLines = lhs.components(separatedBy: .newlines) @@ -34,72 +35,11 @@ extension CollectionDifference { } } -/// Loads a documentation bundle from the given source URL and creates a documentation context. -func loadBundle(from bundleURL: URL, codeListings: [String : AttributedCodeListing] = [:], externalResolvers: [String: ExternalReferenceResolver] = [:], externalSymbolResolver: ExternalSymbolResolver? = nil, diagnosticFilterLevel: DiagnosticSeverity = .hint, configureContext: ((DocumentationContext) throws -> Void)? = nil) throws -> (URL, DocumentationBundle, DocumentationContext) { - let workspace = DocumentationWorkspace() - let context = try DocumentationContext(dataProvider: workspace, diagnosticEngine: DiagnosticEngine(filterLevel: diagnosticFilterLevel)) - context.externalReferenceResolvers = externalResolvers - context.externalSymbolResolver = externalSymbolResolver - context.externalMetadata.diagnosticLevel = diagnosticFilterLevel - try configureContext?(context) - // Load the bundle using automatic discovery - let automaticDataProvider = try LocalFileSystemDataProvider(rootURL: bundleURL) - // Mutate the bundle to include the code listings, then apply to the workspace using a manual provider. - var bundle = try automaticDataProvider.bundles().first! - bundle.attributedCodeListings = codeListings - let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) - try workspace.registerProvider(dataProvider) - return (bundleURL, bundle, context) -} - -func testBundleAndContext(copying name: String, excludingPaths excludedPaths: [String] = [], codeListings: [String : AttributedCodeListing] = [:], externalResolvers: [BundleIdentifier : ExternalReferenceResolver] = [:], externalSymbolResolver: ExternalSymbolResolver? = nil, configureBundle: ((URL) throws -> Void)? = nil) throws -> (URL, DocumentationBundle, DocumentationContext) { - let sourceURL = Bundle.module.url( - forResource: name, withExtension: "docc", subdirectory: "Test Bundles")! - let bundleURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString.appending(".docc"))) - - if FileManager.default.fileExists(atPath: sourceURL.path) { - try FileManager.default.copyItem(at: sourceURL, to: bundleURL) - } else { - try FileManager.default.createDirectory(at: bundleURL, withIntermediateDirectories: true, attributes: nil) - } - - for path in excludedPaths { - try FileManager.default.removeItem(at: bundleURL.appendingPathComponent(path)) - } - - // Do any additional setup to the custom bundle - adding, modifying files, etc - try configureBundle?(bundleURL) - - return try loadBundle(from: bundleURL, codeListings: codeListings, externalResolvers: externalResolvers, externalSymbolResolver: externalSymbolResolver) -} - - -func testBundleAndContext(named name: String, codeListings: [String : AttributedCodeListing] = [:], externalResolvers: [String: ExternalReferenceResolver] = [:]) throws -> (DocumentationBundle, DocumentationContext) { - let bundleURL = Bundle.module.url( - forResource: name, withExtension: "docc", subdirectory: "Test Bundles")! - let (_, bundle, context) = try loadBundle(from: bundleURL, codeListings: codeListings, externalResolvers: externalResolvers) - return (bundle, context) -} - -func testBundle(named name: String) -> DocumentationBundle { - let (bundle, _) = try! testBundleAndContext(named: name) - return bundle -} - -func testBundleFromRootURL(named name: String) throws -> DocumentationBundle { - let bundleURL = Bundle.module.url( - forResource: name, withExtension: "docc", subdirectory: "Test Bundles")! - let dataProvider = try LocalFileSystemDataProvider(rootURL: bundleURL) - - let bundles = try dataProvider.bundles() - return bundles[0] -} - class DocumentationContextTests: XCTestCase { func testResolve() throws { let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) @@ -517,9 +457,7 @@ class DocumentationContextTests: XCTestCase { ]), InfoPlist(displayName: "TestBundle", identifier: "com.test.example"), ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let bundleURL = try exampleDocumentation.write(inside: tempURL) @@ -544,7 +482,7 @@ class DocumentationContextTests: XCTestCase { func testRegisteredImages() throws { let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) @@ -575,7 +513,7 @@ class DocumentationContextTests: XCTestCase { func testDownloadAssets() throws { let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) @@ -632,9 +570,7 @@ class DocumentationContextTests: XCTestCase { ]) ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let workspaceURL = try workspaceContent.write(inside: tempURL) let dataProvider = try LocalFileSystemDataProvider(rootURL: workspaceURL) @@ -665,7 +601,7 @@ class DocumentationContextTests: XCTestCase { context.addGlobalChecks([{ (context, reference) -> [Problem] in return [Problem(diagnostic: Diagnostic(source: reference.url, severity: DiagnosticSeverity.error, range: nil, identifier: "com.tests.testGraphChecks", summary: "test error"), possibleSolutions: [])] }]) - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) @@ -700,10 +636,7 @@ class DocumentationContextTests: XCTestCase { ]) ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } - + let tempURL = try createTemporaryDirectory() let bundleURL = try testBundle.write(inside: tempURL) let workspace = DocumentationWorkspace() @@ -731,10 +664,7 @@ class DocumentationContextTests: XCTestCase { ]) ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } - + let tempURL = try createTemporaryDirectory() let bundleURL = try testBundle.write(inside: tempURL) let workspace = DocumentationWorkspace() @@ -972,10 +902,7 @@ class DocumentationContextTests: XCTestCase { ]), ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } - + let tempURL = try createTemporaryDirectory() let bundleURL = try testBundle.write(inside: tempURL) let workspace = DocumentationWorkspace() @@ -1038,10 +965,7 @@ class DocumentationContextTests: XCTestCase { ]) ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } - + let tempURL = try createTemporaryDirectory() let bundleURL = try testBundle.write(inside: tempURL) let workspace = DocumentationWorkspace() @@ -1075,10 +999,7 @@ class DocumentationContextTests: XCTestCase { ]) ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } - + let tempURL = try createTemporaryDirectory() let bundleURL = try testBundle.write(inside: tempURL) let workspace = DocumentationWorkspace() @@ -1115,10 +1036,7 @@ class DocumentationContextTests: XCTestCase { ]) ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } - + let tempURL = try createTemporaryDirectory() let bundleURL = try testBundle.write(inside: tempURL) let workspace = DocumentationWorkspace() @@ -1159,10 +1077,7 @@ class DocumentationContextTests: XCTestCase { ]) ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } - + let tempURL = try createTemporaryDirectory() let bundleURL = try testBundle.write(inside: tempURL) let workspace = DocumentationWorkspace() @@ -1350,7 +1265,7 @@ let expected = """ func testLanguageForNode() throws { let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) let articleReference = ResolvedTopicReference(bundleIdentifier: bundle.identifier, path: "/documentation/Test-Bundle/article", sourceLanguage: .swift) @@ -1910,11 +1825,7 @@ let expected = """ ("file:///path with spaces/to/file.swift", "file:///path%20with%20spaces/to/file.swift"), ] { // Create an empty bundle - let targetURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString.appending(".docc")) - try FileManager.default.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: targetURL) - } + let targetURL = try createTemporaryDirectory(named: "test.docc") // Copy test Info.plist try FileManager.default.copyItem(at: Bundle.module.url( @@ -2027,7 +1938,7 @@ let expected = """ func renderNodeForPath(path: String) throws -> (DocumentationNode, RenderNode) { let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) @@ -2070,9 +1981,7 @@ let expected = """ func testCrossSymbolGraphPathCollisions() throws { // Create temp folder - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString)) - try FileManager.default.createDirectory(atPath: tempURL.path, withIntermediateDirectories: false, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() // Create test bundle let bundleURL = try Folder(name: "collisions.docc", content: [ @@ -2162,9 +2071,7 @@ let expected = """ /// rdar://69242313 func testLinkResolutionDoesNotSkipSymbolGraph() throws { - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString)) - try FileManager.default.createDirectory(atPath: tempURL.path, withIntermediateDirectories: false, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let bundleURL = try Folder(name: "Missing.docc", content: [ InfoPlist(displayName: "MissingDocs", identifier: "com.test.missing-docs"), @@ -2278,9 +2185,7 @@ let expected = """ } func testLinkResolutionDiagnosticsEmittedForTechnologyPages() throws { - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString)) - try FileManager.default.createDirectory(atPath: tempURL.path, withIntermediateDirectories: false, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let bundleURL = try Folder(name: "module-links.docc", content: [ InfoPlist(displayName: "Test", identifier: "com.test.docc"), @@ -2343,10 +2248,7 @@ let expected = """ """), InfoPlist(displayName: "MyKit", identifier: "com.test.MyKit"), ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } - + let tempURL = try createTemporaryDirectory() let bundleURL = try exampleDocumentation.write(inside: tempURL) // Parse this test content @@ -2438,9 +2340,7 @@ let expected = """ """) do { - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString)) - try FileManager.default.createDirectory(atPath: tempURL.path, withIntermediateDirectories: false, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let bundleURL = try Folder(name: "Module.docc", content: [ InfoPlist(displayName: "Module", identifier: "org.swift.docc.example"), @@ -2476,9 +2376,7 @@ let expected = """ } do { - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString)) - try FileManager.default.createDirectory(atPath: tempURL.path, withIntermediateDirectories: false, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let bundleURL = try Folder(name: "Module.docc", content: [ InfoPlist(displayName: "Module", identifier: "org.swift.docc.example"), @@ -2509,9 +2407,7 @@ let expected = """ } func testAutomaticTaskGroupsPlacedAfterManualCuration() throws { - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString)) - try FileManager.default.createDirectory(atPath: tempURL.path, withIntermediateDirectories: false, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let bundleURL = try Folder(name: "Module.docc", content: [ InfoPlist(displayName: "Module", identifier: "org.swift.docc.example"), @@ -2722,9 +2618,8 @@ let expected = """ TextFile(name: "TestTechnology.tutorial", utf8Content: testTechnologySource), TextFile(name: "Test.tutorial", utf8Content: testTutorialSource), ]) - let tempFolderURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString.appending(".docc"))) + let tempFolderURL = try createTemporaryDirectory().appendingPathComponent("test.docc") try testBundle.write(to: tempFolderURL) - defer { try? FileManager.default.removeItem(at: tempFolderURL) } // Load the bundle let (_, bundle, context) = try loadBundle(from: tempFolderURL) @@ -2760,9 +2655,8 @@ let expected = """ TextFile(name: "TestTechnology.tutorial", utf8Content: testTechnologySource), TextFile(name: "Test.tutorial", utf8Content: testTutorialSource), ]) - let tempFolderURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString.appending(".docc"))) + let tempFolderURL = try createTemporaryDirectory().appendingPathComponent("test.docc") try testBundle.write(to: tempFolderURL) - defer { try? FileManager.default.removeItem(at: tempFolderURL) } // Load the bundle let (_, bundle, context) = try loadBundle(from: tempFolderURL) @@ -2821,9 +2715,8 @@ let expected = """ TextFile(name: "TestTechnology.tutorial", utf8Content: testTechnologySource), TextFile(name: "Test.tutorial", utf8Content: testTutorialSource), ]) - let tempFolderURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString.appending(".docc"))) + let tempFolderURL = try createTemporaryDirectory().appendingPathComponent("test.docc") try testBundle.write(to: tempFolderURL) - defer { try? FileManager.default.removeItem(at: tempFolderURL) } // Load the bundle let (_, bundle, context) = try loadBundle(from: tempFolderURL) @@ -2892,9 +2785,8 @@ let expected = """ CopyOfFile(original: infoPlistURL, newName: "Info.plist"), TextFile(name: "TestFramework.symbols.json", utf8Content: symbolGraphFixture), ]) - let tempFolderURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString.appending(".docc"))) + let tempFolderURL = try createTemporaryDirectory().appendingPathComponent("test.docc") try testBundle.write(to: tempFolderURL) - defer { try? FileManager.default.removeItem(at: tempFolderURL) } // Load the bundle let (_, bundle, context) = try loadBundle(from: tempFolderURL) @@ -2931,9 +2823,7 @@ let expected = """ /// ``` func testWarningForUnresolvableLinksInInheritedDocs() throws { // Create temp folder - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString)) - try FileManager.default.createDirectory(atPath: tempURL.path, withIntermediateDirectories: false, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() // Create test bundle let bundleURL = try Folder(name: "InheritedDocs.docc", content: [ @@ -3015,10 +2905,7 @@ let expected = """ InfoPlist(displayName: "TestBundle", identifier: "com.test.example") ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } - + let tempURL = try createTemporaryDirectory() let bundleURL = try exampleDocumentation.write(inside: tempURL) let workspace = DocumentationWorkspace() diff --git a/Tests/SwiftDocCTests/Infrastructure/DocumentationCuratorTests.swift b/Tests/SwiftDocCTests/Infrastructure/DocumentationCuratorTests.swift index c52d861eaf..7f6e7a4c27 100644 --- a/Tests/SwiftDocCTests/Infrastructure/DocumentationCuratorTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/DocumentationCuratorTests.swift @@ -29,7 +29,7 @@ class DocumentationCuratorTests: XCTestCase { func testCrawl() throws { let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) @@ -81,14 +81,11 @@ class DocumentationCuratorTests: XCTestCase { let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString).appendingPathComponent("unit-test.docc") + let tempURL = try createTemporaryDirectory().appendingPathComponent("unit-test.docc") let testBundleURL = Bundle.module.url( forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! XCTAssert(FileManager.default.fileExists(atPath: testBundleURL.path)) - - try FileManager.default.createDirectory(at: tempURL.deletingLastPathComponent(), withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL.deletingLastPathComponent()) } try FileManager.default.copyItem(at: testBundleURL, to: tempURL) let sidecarFile = tempURL.appendingPathComponent("documentation/myfunction.md") @@ -151,7 +148,7 @@ class DocumentationCuratorTests: XCTestCase { func testSymbolLinkResolving() throws { let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) @@ -208,7 +205,7 @@ class DocumentationCuratorTests: XCTestCase { func testLinkResolving() throws { let workspace = DocumentationWorkspace() let context = try DocumentationContext(dataProvider: workspace) - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let sourceRoot = Bundle.module.url( forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) diff --git a/Tests/SwiftDocCTests/Infrastructure/ExternalReferenceResolverTests.swift b/Tests/SwiftDocCTests/Infrastructure/ExternalReferenceResolverTests.swift index abb47c3308..8f65edcde8 100644 --- a/Tests/SwiftDocCTests/Infrastructure/ExternalReferenceResolverTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/ExternalReferenceResolverTests.swift @@ -101,9 +101,8 @@ class ExternalReferenceResolverTests: XCTestCase { forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! // Create a copy of the test bundle - let bundleURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString.appending(".docc")) + let bundleURL = try createTemporaryDirectory().appendingPathComponent("test.docc") try FileManager.default.copyItem(at: sourceURL, to: bundleURL) - defer { try? FileManager.default.removeItem(at: bundleURL) } // Add external link let myClassMDURL = bundleURL.appendingPathComponent("documentation").appendingPathComponent("myclass.md") @@ -146,7 +145,7 @@ class ExternalReferenceResolverTests: XCTestCase { func testResolvesReferencesExternallyOnlyWhenFallbackResolversAreSet() throws { let workspace = DocumentationWorkspace() - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) let context = try DocumentationContext(dataProvider: workspace) @@ -190,7 +189,7 @@ class ExternalReferenceResolverTests: XCTestCase { func testLoadEntityForExternalReference() throws { let workspace = DocumentationWorkspace() - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) let context = try DocumentationContext(dataProvider: workspace) @@ -238,7 +237,7 @@ Document @1:1-1:35 externalResolver.resolvedEntityKind = resolvedEntityKind context.externalReferenceResolvers = [externalResolver.bundleIdentifier: externalResolver] - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) try workspace.registerProvider(dataProvider) diff --git a/Tests/SwiftDocCTests/Infrastructure/InheritIntroducedAvailabilityTests.swift b/Tests/SwiftDocCTests/Infrastructure/InheritIntroducedAvailabilityTests.swift index c00d76215f..50d24b91fe 100644 --- a/Tests/SwiftDocCTests/Infrastructure/InheritIntroducedAvailabilityTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/InheritIntroducedAvailabilityTests.swift @@ -33,7 +33,20 @@ fileprivate extension SymbolGraph.Symbol { class InheritIntroducedAvailabilityTests: XCTestCase { typealias Domain = SymbolGraph.Symbol.Availability.Domain typealias Version = SymbolGraph.SemanticVersion - let (testBundle, context) = try! testBundleAndContext(named: "TestBundle") + + var testBundle: DocumentationBundle! + var context: DocumentationContext! + + override func setUpWithError() throws { + try super.setUpWithError() + (testBundle, context) = try testBundleAndContext(named: "TestBundle") + } + + override func tearDown() { + testBundle = nil + context = nil + super.tearDown() + } /// Tests that the `introduced` availability version comes from /// the macOS version in the Info.plist diff --git a/Tests/SwiftDocCTests/Infrastructure/NodeTagsTests.swift b/Tests/SwiftDocCTests/Infrastructure/NodeTagsTests.swift index 617a8bb47d..f2dcc9470a 100644 --- a/Tests/SwiftDocCTests/Infrastructure/NodeTagsTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/NodeTagsTests.swift @@ -10,6 +10,7 @@ import XCTest @testable import SwiftDocC +import SwiftDocCTestUtilities class NodeTagsTests: XCTestCase { func testSPIMetadata() throws { @@ -20,9 +21,8 @@ class NodeTagsTests: XCTestCase { InfoPlist(displayName: "spi", identifier: "com.tests.spi"), CopyOfFile(original: spiSGURL), ]) - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString.appending("unit-tests.docc")) + let tempURL = try createTemporaryDirectory().appendingPathComponent("unit-tests.docc") try bundleFolder.write(to: tempURL) - defer { try? FileManager.default.removeItem(at: tempURL) } let (_, bundle, context) = try loadBundle(from: tempURL) diff --git a/Tests/SwiftDocCTests/Infrastructure/SymbolGraph/SymbolGraphLoaderTests.swift b/Tests/SwiftDocCTests/Infrastructure/SymbolGraph/SymbolGraphLoaderTests.swift index d9b1faf16f..1706e65c9e 100644 --- a/Tests/SwiftDocCTests/Infrastructure/SymbolGraph/SymbolGraphLoaderTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/SymbolGraph/SymbolGraphLoaderTests.swift @@ -12,14 +12,12 @@ import Foundation import XCTest @testable import SymbolKit @testable import SwiftDocC +import SwiftDocCTestUtilities class SymbolGraphLoaderTests: XCTestCase { func testLoadingDifferentModules() throws { - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() var symbolGraphURLs = [URL]() for moduleNames in ["One", "Two", "Three"] { @@ -59,10 +57,7 @@ class SymbolGraphLoaderTests: XCTestCase { } func testLoadingDifferentModuleExtensions() throws { - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() var symbolGraphURLs = [URL]() for moduleName in ["One", "Two", "Three"] { @@ -89,10 +84,7 @@ class SymbolGraphLoaderTests: XCTestCase { } func testNotGroupingExtensionsWithWithTheModuleThatExtends() throws { - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() var symbolGraphURLs = [URL]() @@ -130,10 +122,7 @@ class SymbolGraphLoaderTests: XCTestCase { } func testLoadingHighNumberOfModulesConcurrently() throws { - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let symbolGraphSourceURL = Bundle.module.url( forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! diff --git a/Tests/SwiftDocCTests/Infrastructure/SymbolGraph/SymbolGraphRelationshipsBuilderTests.swift b/Tests/SwiftDocCTests/Infrastructure/SymbolGraph/SymbolGraphRelationshipsBuilderTests.swift index 4b6bc6ae5f..392b5e27bf 100644 --- a/Tests/SwiftDocCTests/Infrastructure/SymbolGraph/SymbolGraphRelationshipsBuilderTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/SymbolGraph/SymbolGraphRelationshipsBuilderTests.swift @@ -48,7 +48,7 @@ class SymbolGraphRelationshipsBuilderTests: XCTestCase { } func testConformsRelationship() throws { - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") var symbolIndex = [String: DocumentationNode]() let engine = DiagnosticEngine() @@ -77,7 +77,7 @@ class SymbolGraphRelationshipsBuilderTests: XCTestCase { } func testInheritanceRelationship() throws { - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") var symbolIndex = [String: DocumentationNode]() let engine = DiagnosticEngine() @@ -106,7 +106,7 @@ class SymbolGraphRelationshipsBuilderTests: XCTestCase { } func testRequirementRelationship() throws { - let bundle = testBundle(named: "TestBundle") + let bundle = try testBundle(named: "TestBundle") var symbolIndex = [String: DocumentationNode]() let engine = DiagnosticEngine() diff --git a/Tests/SwiftDocCTests/Infrastructure/SymbolReferenceTests.swift b/Tests/SwiftDocCTests/Infrastructure/SymbolReferenceTests.swift index 64efe1f311..95549eb053 100644 --- a/Tests/SwiftDocCTests/Infrastructure/SymbolReferenceTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/SymbolReferenceTests.swift @@ -11,6 +11,7 @@ import XCTest @testable import SymbolKit @testable import SwiftDocC +import SwiftDocCTestUtilities class SymbolReferenceTests: XCTestCase { func testUsesIdentifierForUnresolvedSymbols() { @@ -197,10 +198,7 @@ class SymbolReferenceTests: XCTestCase { ]), ]) - let tempURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } - + let tempURL = try createTemporaryDirectory() let bundleURL = try testBundle.write(inside: tempURL) let workspace = DocumentationWorkspace() diff --git a/Tests/SwiftDocCTests/LinkTargets/LinkDestinationSummaryTests.swift b/Tests/SwiftDocCTests/LinkTargets/LinkDestinationSummaryTests.swift index 43cb99525e..d1158e8f50 100644 --- a/Tests/SwiftDocCTests/LinkTargets/LinkDestinationSummaryTests.swift +++ b/Tests/SwiftDocCTests/LinkTargets/LinkDestinationSummaryTests.swift @@ -10,6 +10,7 @@ import XCTest @testable import SwiftDocC +import SwiftDocCTestUtilities class ExternalLinkableTests: XCTestCase { @@ -335,23 +336,4 @@ class ExternalLinkableTests: XCTestCase { XCTAssert(decoded.variants.isEmpty) } - - // Workaround that addTeardownBlock doesn't exist in swift-corelibs-xctest - - private var tempFilesToRemove: [URL] = [] - - override func tearDown() { - for url in tempFilesToRemove { - try? FileManager.default.removeItem(at: url) - } - tempFilesToRemove.removeAll() - super.tearDown() - } - - func createTemporaryDirectory() throws -> URL { - let url = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil) - tempFilesToRemove.append(url) - return url - } } diff --git a/Tests/SwiftDocCTests/Model/LineHighlighterTests.swift b/Tests/SwiftDocCTests/Model/LineHighlighterTests.swift index 91ff565101..ae76be6cba 100644 --- a/Tests/SwiftDocCTests/Model/LineHighlighterTests.swift +++ b/Tests/SwiftDocCTests/Model/LineHighlighterTests.swift @@ -11,9 +11,9 @@ import XCTest @testable import SwiftDocC import Markdown +import SwiftDocCTestUtilities class LineHighlighterTests: XCTestCase { - static var tempFilesToRemove = [URL]() static let bundleIdentifier = "org.swift.docc.LineHighlighterTests" static let defaultOverview = TextFile(name: "TechnologyX.tutorial", utf8Content: """ @Technology(name: "TechnologyX") { @@ -49,14 +49,7 @@ class LineHighlighterTests: XCTestCase { ]) } - static func createTemporaryDirectory() throws -> URL { - let url = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil) - LineHighlighterTests.tempFilesToRemove.append(url) - return url - } - - static func testBundleAndContext(bundleRoot: Folder, bundleIdentifier: BundleIdentifier) throws -> (DocumentationBundle, DocumentationContext) { + func testBundleAndContext(bundleRoot: Folder, bundleIdentifier: BundleIdentifier) throws -> (DocumentationBundle, DocumentationContext) { let workspace = DocumentationWorkspace() let context = try! DocumentationContext(dataProvider: workspace) @@ -68,7 +61,7 @@ class LineHighlighterTests: XCTestCase { return (bundle, context) } - static func highlights(tutorialFile: TextFile, codeFiles: [TextFile]) throws -> [LineHighlighter.Result] { + func highlights(tutorialFile: TextFile, codeFiles: [TextFile]) throws -> [LineHighlighter.Result] { let bundleFolder = LineHighlighterTests.bundleFolder(tutorial: tutorialFile, codeFiles: codeFiles) let (bundle, context) = try testBundleAndContext(bundleRoot: bundleFolder, bundleIdentifier: LineHighlighterTests.bundleIdentifier) @@ -91,7 +84,7 @@ class LineHighlighterTests: XCTestCase { @Assessments } """) - XCTAssertTrue(try LineHighlighterTests.highlights(tutorialFile: tutorialFile, codeFiles: []).isEmpty) + XCTAssertTrue(try highlights(tutorialFile: tutorialFile, codeFiles: []).isEmpty) } func testOneStep() throws { @@ -113,7 +106,7 @@ class LineHighlighterTests: XCTestCase { @Assessments """) let code1 = TextFile(name: "code1.swift", utf8Content: "func foo() {}") - let results = try LineHighlighterTests.highlights(tutorialFile: tutorialFile, codeFiles: [code1]) + let results = try highlights(tutorialFile: tutorialFile, codeFiles: [code1]) XCTAssertEqual(1, results.count) results.first.map { result in XCTAssertEqual(ResourceReference(bundleIdentifier: LineHighlighterTests.bundleIdentifier, path: code1.name), result.file) @@ -142,7 +135,7 @@ class LineHighlighterTests: XCTestCase { """) let code0 = TextFile(name: "code0.swift", utf8Content: "func foo() {}") let code1 = TextFile(name: "code1.swift", utf8Content: "func foo() {}\nfunc bar() {}") - let results = try LineHighlighterTests.highlights(tutorialFile: tutorialFile, codeFiles: [code0, code1]) + let results = try highlights(tutorialFile: tutorialFile, codeFiles: [code0, code1]) XCTAssertEqual(1, results.count) results.first.map { result in XCTAssertEqual(ResourceReference(bundleIdentifier: LineHighlighterTests.bundleIdentifier, path: code1.name), result.file) @@ -181,7 +174,7 @@ class LineHighlighterTests: XCTestCase { let code1 = TextFile(name: "code1.swift", utf8Content: "func foo() {}") let code2 = TextFile(name: "code2.swift", utf8Content: "func foo() {}\nfunc bar() {}") - let results = try LineHighlighterTests.highlights(tutorialFile: tutorialFile, codeFiles: [code1, code2]) + let results = try highlights(tutorialFile: tutorialFile, codeFiles: [code1, code2]) XCTAssertEqual(2, results.count) XCTAssertEqual(ResourceReference(bundleIdentifier: LineHighlighterTests.bundleIdentifier, path: code1.name), results[0].file) @@ -211,7 +204,7 @@ class LineHighlighterTests: XCTestCase { """) let code0 = TextFile(name: "code0.swift", utf8Content: "func foo() {}") let code1 = TextFile(name: "code1.swift", utf8Content: "func foo() {}\nfunc bar() {}") - let results = try LineHighlighterTests.highlights(tutorialFile: tutorialFile, codeFiles: [code0, code1]) + let results = try highlights(tutorialFile: tutorialFile, codeFiles: [code0, code1]) XCTAssertEqual(1, results.count) results.first.map { result in XCTAssertEqual(ResourceReference(bundleIdentifier: LineHighlighterTests.bundleIdentifier, path: code1.name), result.file) @@ -243,7 +236,7 @@ class LineHighlighterTests: XCTestCase { """) let code1 = TextFile(name: "code1.swift", utf8Content: "func foo() {}") let code2 = TextFile(name: "code2.swift", utf8Content: "func foo() {}\nfunc bar() {}") - let results = try LineHighlighterTests.highlights(tutorialFile: tutorialFile, codeFiles: [code1, code2]) + let results = try highlights(tutorialFile: tutorialFile, codeFiles: [code1, code2]) XCTAssertEqual(2, results.count) @@ -282,7 +275,7 @@ class LineHighlighterTests: XCTestCase { let code0 = TextFile(name: "code0.swift", utf8Content: "") let code1 = TextFile(name: "code1.swift", utf8Content: "func foo() {}") let code2 = TextFile(name: "code2.swift", utf8Content: "func foo() {}\nfunc bar() {}") - let results = try LineHighlighterTests.highlights(tutorialFile: tutorialFile, codeFiles: [code0, code1, code2]) + let results = try highlights(tutorialFile: tutorialFile, codeFiles: [code0, code1, code2]) XCTAssertEqual(2, results.count) @@ -297,12 +290,4 @@ class LineHighlighterTests: XCTestCase { XCTAssertNil(highlight.length) } } - - override func tearDown() { - for url in LineHighlighterTests.tempFilesToRemove { - try? FileManager.default.removeItem(at: url) - } - LineHighlighterTests.tempFilesToRemove.removeAll() - super.tearDown() - } } diff --git a/Tests/SwiftDocCTests/Model/SemaToRenderNodeMultiLanguageTests.swift b/Tests/SwiftDocCTests/Model/SemaToRenderNodeMultiLanguageTests.swift index 529c526f0b..a9bffec963 100644 --- a/Tests/SwiftDocCTests/Model/SemaToRenderNodeMultiLanguageTests.swift +++ b/Tests/SwiftDocCTests/Model/SemaToRenderNodeMultiLanguageTests.swift @@ -64,7 +64,7 @@ class SemaToRenderNodeMixedLanguageTests: ExperimentalObjectiveCTestCase { } func testOutputsMultiLanguageRenderNodes() throws { - let outputConsumer = try TestRenderNodeOutputConsumer.mixedLanguageFrameworkConsumer() + let outputConsumer = try mixedLanguageFrameworkConsumer() XCTAssertEqual( Set( @@ -119,7 +119,7 @@ class SemaToRenderNodeMixedLanguageTests: ExperimentalObjectiveCTestCase { } func testFrameworkRenderNodeHasExpectedContentAcrossLanguages() throws { - let outputConsumer = try TestRenderNodeOutputConsumer.mixedLanguageFrameworkConsumer() + let outputConsumer = try mixedLanguageFrameworkConsumer() let mixedLanguageFrameworkRenderNode = try outputConsumer.renderNode( withIdentifier: "MixedLanguageFramework" ) @@ -204,7 +204,7 @@ class SemaToRenderNodeMixedLanguageTests: ExperimentalObjectiveCTestCase { } func testObjectiveCAuthoredRenderNodeHasExpectedContentAcrossLanguages() throws { - let outputConsumer = try TestRenderNodeOutputConsumer.mixedLanguageFrameworkConsumer() + let outputConsumer = try mixedLanguageFrameworkConsumer() let fooRenderNode = try outputConsumer.renderNode(withIdentifier: "c:@E@Foo") assertExpectedContent( @@ -455,8 +455,10 @@ extension TestRenderNodeOutputConsumer { return try XCTUnwrap(renderNode) } - - static func mixedLanguageFrameworkConsumer() throws -> TestRenderNodeOutputConsumer { +} + +fileprivate extension SemaToRenderNodeMixedLanguageTests { + func mixedLanguageFrameworkConsumer() throws -> TestRenderNodeOutputConsumer { let (bundleURL, _, context) = try testBundleAndContext(copying: "MixedLanguageFramework") var converter = DocumentationConverter( diff --git a/Tests/SwiftDocCTests/Model/SemaToRenderNodeTests.swift b/Tests/SwiftDocCTests/Model/SemaToRenderNodeTests.swift index b28d3aa0d3..ce9ad2561f 100644 --- a/Tests/SwiftDocCTests/Model/SemaToRenderNodeTests.swift +++ b/Tests/SwiftDocCTests/Model/SemaToRenderNodeTests.swift @@ -1796,7 +1796,7 @@ Document @1:1-11:19 // Overwrite the article so we can test the article eyebrow for articles without task groups let sourceURL = Bundle.module.url( forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString).appendingPathExtension("docc") + let targetURL = try createTemporaryDirectory().appendingPathComponent("test.docc") try FileManager.default.copyItem(at: sourceURL, to: targetURL) diff --git a/Tests/SwiftDocCTests/Rendering/DefaultAvailabilityTests.swift b/Tests/SwiftDocCTests/Rendering/DefaultAvailabilityTests.swift index 6a5902a550..417167b056 100644 --- a/Tests/SwiftDocCTests/Rendering/DefaultAvailabilityTests.swift +++ b/Tests/SwiftDocCTests/Rendering/DefaultAvailabilityTests.swift @@ -16,8 +16,8 @@ import SymbolKit class DefaultAvailabilityTests: XCTestCase { // Test whether missing default availability key correctly produces nil availability - func testBundleWithoutDefaultAvailability() { - let bundle = testBundle(named: "BundleWithoutAvailability") + func testBundleWithoutDefaultAvailability() throws { + let bundle = try testBundle(named: "BundleWithoutAvailability") XCTAssertNil(bundle.info.defaultAvailability) } diff --git a/Tests/SwiftDocCTests/Rendering/PlistSymbolTests.swift b/Tests/SwiftDocCTests/Rendering/PlistSymbolTests.swift index dcdf7a2145..0ef19b21e6 100644 --- a/Tests/SwiftDocCTests/Rendering/PlistSymbolTests.swift +++ b/Tests/SwiftDocCTests/Rendering/PlistSymbolTests.swift @@ -11,6 +11,7 @@ import Foundation import XCTest @testable import SwiftDocC +import SwiftDocCTestUtilities class PlistSymbolTests: XCTestCase { private let plistSymbolURL = Bundle.module.url( @@ -126,10 +127,10 @@ class PlistSymbolTests: XCTestCase { let modifiedJSON = try String(contentsOf: plistSymbolURL) .replacingOccurrences(of: "\"ideTitle\": \"WiFi access\",", with: "") - let tempDir = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ TextFile(name: "missingIdeTitle.json", utf8Content: modifiedJSON), ]) - let symbol = try RenderNode.decode(fromJSON: try Data(contentsOf: tempDir.url.appendingPathComponent("missingIdeTitle.json"))) + let symbol = try RenderNode.decode(fromJSON: try Data(contentsOf: tempFolderURL.appendingPathComponent("missingIdeTitle.json"))) // // Plist Details @@ -152,10 +153,10 @@ class PlistSymbolTests: XCTestCase { let modifiedJSON = try String(contentsOf: plistSymbolURL) .replacingOccurrences(of: "\"title\": \"Possible Values\",", with: "") - let tempDir = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ TextFile(name: "missingPossibleValuesTitle.json", utf8Content: modifiedJSON), ]) - let symbol = try RenderNode.decode(fromJSON: try Data(contentsOf: tempDir.url.appendingPathComponent("missingPossibleValuesTitle.json"))) + let symbol = try RenderNode.decode(fromJSON: try Data(contentsOf: tempFolderURL.appendingPathComponent("missingPossibleValuesTitle.json"))) // // Plist Details diff --git a/Tests/SwiftDocCTests/Semantics/SymbolTests.swift b/Tests/SwiftDocCTests/Semantics/SymbolTests.swift index 62e64573e4..95932d41a4 100644 --- a/Tests/SwiftDocCTests/Semantics/SymbolTests.swift +++ b/Tests/SwiftDocCTests/Semantics/SymbolTests.swift @@ -12,6 +12,7 @@ import XCTest @testable import SymbolKit @testable import SwiftDocC import Markdown +import SwiftDocCTestUtilities class SymbolTests: XCTestCase { @@ -499,9 +500,7 @@ class SymbolTests: XCTestCase { } func testWarningWhenDocCommentContainsDirectiveInSubclass() throws { - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString)) - try FileManager.default.createDirectory(atPath: tempURL.path, withIntermediateDirectories: false, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let bundleURL = try Folder(name: "Inheritance.docc", content: [ InfoPlist(displayName: "Inheritance", identifier: "com.test.inheritance"), diff --git a/Tests/SwiftDocCTests/ShadowFileManagerTemporaryDirectory.swift b/Tests/SwiftDocCTests/ShadowFileManagerTemporaryDirectory.swift new file mode 100644 index 0000000000..c7602c156f --- /dev/null +++ b/Tests/SwiftDocCTests/ShadowFileManagerTemporaryDirectory.swift @@ -0,0 +1,23 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation +import XCTest + +// This file exists to shadow `FileManager.temporaryDirectory` in unit tests to warn about potentially referencing a shared location if multiple checkouts run tests at the same time in Swift CI. + +extension FileManager { + + @available(*, deprecated, message: "Use `createTemporaryDirectory` instead in unit tests to avoid referencing a shared location in Swift CI.") + var temporaryDirectory: URL { + XCTFail("Use `createTemporaryDirectory` instead in unit tests to avoid referencing a shared location in Swift CI.") + return URL(fileURLWithPath: Foundation.NSTemporaryDirectory()) + } +} diff --git a/Tests/SwiftDocCTests/Utility/LMDBTests.swift b/Tests/SwiftDocCTests/Utility/LMDBTests.swift index 5ce1a5dc33..2050311d82 100644 --- a/Tests/SwiftDocCTests/Utility/LMDBTests.swift +++ b/Tests/SwiftDocCTests/Utility/LMDBTests.swift @@ -11,31 +11,18 @@ import XCTest @testable import SwiftDocC +import SwiftDocCTestUtilities final class SwiftLMDBTests: XCTestCase { - - let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - - /// Convenience var for path. - var tmpPath: String { - return temporaryDirectoryURL.path - } - var environment: LMDB.Environment! - override func setUp() { - if !FileManager.default.fileExists(atPath: temporaryDirectoryURL.path) { - try? FileManager.default.createDirectory(at: temporaryDirectoryURL, withIntermediateDirectories: false, attributes: nil) - } else { - try? FileManager.default.removeItem(at: temporaryDirectoryURL) - try? FileManager.default.createDirectory(at: temporaryDirectoryURL, withIntermediateDirectories: false, attributes: nil) - } + override func setUpWithError() throws { + let tempURL = try createTemporaryDirectory() - environment = try! LMDB.Environment(path: tmpPath, maxDBs: 4, mapSize: 1024 * 1024 * 1024) // 1GB of mapSize + environment = try! LMDB.Environment(path: tempURL.path, maxDBs: 4, mapSize: 1024 * 1024 * 1024) // 1GB of mapSize } override func tearDown() { - try? FileManager.default.removeItem(at: temporaryDirectoryURL) environment = nil } @@ -44,7 +31,7 @@ final class SwiftLMDBTests: XCTestCase { func testVersion() { let version = LMDB.default.version - // Ensure the LMDB library version is the exptected one: 0.9.70 + // Ensure the LMDB library version is the expected one: 0.9.70 XCTAssertEqual(version.description, "0.9.70") } diff --git a/Tests/SwiftDocCTests/XCTestCase+LoadingTestData.swift b/Tests/SwiftDocCTests/XCTestCase+LoadingTestData.swift new file mode 100644 index 0000000000..945c73cd81 --- /dev/null +++ b/Tests/SwiftDocCTests/XCTestCase+LoadingTestData.swift @@ -0,0 +1,79 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation +import XCTest +@testable import SwiftDocC + +extension XCTestCase { + + /// Loads a documentation bundle from the given source URL and creates a documentation context. + func loadBundle(from bundleURL: URL, codeListings: [String : AttributedCodeListing] = [:], externalResolvers: [String: ExternalReferenceResolver] = [:], externalSymbolResolver: ExternalSymbolResolver? = nil, diagnosticFilterLevel: DiagnosticSeverity = .hint, configureContext: ((DocumentationContext) throws -> Void)? = nil) throws -> (URL, DocumentationBundle, DocumentationContext) { + let workspace = DocumentationWorkspace() + let context = try DocumentationContext(dataProvider: workspace, diagnosticEngine: DiagnosticEngine(filterLevel: diagnosticFilterLevel)) + context.externalReferenceResolvers = externalResolvers + context.externalSymbolResolver = externalSymbolResolver + context.externalMetadata.diagnosticLevel = diagnosticFilterLevel + try configureContext?(context) + // Load the bundle using automatic discovery + let automaticDataProvider = try LocalFileSystemDataProvider(rootURL: bundleURL) + // Mutate the bundle to include the code listings, then apply to the workspace using a manual provider. + var bundle = try XCTUnwrap(automaticDataProvider.bundles().first) + bundle.attributedCodeListings = codeListings + let dataProvider = PrebuiltLocalFileSystemDataProvider(bundles: [bundle]) + try workspace.registerProvider(dataProvider) + return (bundleURL, bundle, context) + } + + func testBundleAndContext(copying name: String, excludingPaths excludedPaths: [String] = [], codeListings: [String : AttributedCodeListing] = [:], externalResolvers: [BundleIdentifier : ExternalReferenceResolver] = [:], externalSymbolResolver: ExternalSymbolResolver? = nil, configureBundle: ((URL) throws -> Void)? = nil) throws -> (URL, DocumentationBundle, DocumentationContext) { + let sourceURL = try XCTUnwrap(Bundle.module.url( + forResource: name, withExtension: "docc", subdirectory: "Test Bundles")) + + let sourceExists = FileManager.default.fileExists(atPath: sourceURL.path) + let bundleURL = sourceExists + ? try createTemporaryDirectory().appendingPathComponent("\(name).docc") + : try createTemporaryDirectory(named: "\(name).docc") + + if sourceExists { + try FileManager.default.copyItem(at: sourceURL, to: bundleURL) + } + + for path in excludedPaths { + try FileManager.default.removeItem(at: bundleURL.appendingPathComponent(path)) + } + + // Do any additional setup to the custom bundle - adding, modifying files, etc + try configureBundle?(bundleURL) + + return try loadBundle(from: bundleURL, codeListings: codeListings, externalResolvers: externalResolvers, externalSymbolResolver: externalSymbolResolver) + } + + func testBundleAndContext(named name: String, codeListings: [String : AttributedCodeListing] = [:], externalResolvers: [String: ExternalReferenceResolver] = [:]) throws -> (DocumentationBundle, DocumentationContext) { + let bundleURL = try XCTUnwrap(Bundle.module.url( + forResource: name, withExtension: "docc", subdirectory: "Test Bundles")) + let (_, bundle, context) = try loadBundle(from: bundleURL, codeListings: codeListings, externalResolvers: externalResolvers) + return (bundle, context) + } + + func testBundle(named name: String) throws -> DocumentationBundle { + let (bundle, _) = try testBundleAndContext(named: name) + return bundle + } + + func testBundleFromRootURL(named name: String) throws -> DocumentationBundle { + let bundleURL = try XCTUnwrap(Bundle.module.url( + forResource: name, withExtension: "docc", subdirectory: "Test Bundles")) + let dataProvider = try LocalFileSystemDataProvider(rootURL: bundleURL) + + let bundles = try dataProvider.bundles() + return bundles[0] + } + +} diff --git a/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ConvertSubcommandTests.swift b/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ConvertSubcommandTests.swift index 92437213d8..3be34ed636 100644 --- a/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ConvertSubcommandTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ConvertSubcommandTests.swift @@ -11,6 +11,7 @@ import XCTest @testable import SwiftDocCUtilities @testable import SwiftDocC +import SwiftDocCTestUtilities class ConvertSubcommandTests: XCTestCase { private let testBundleURL = Bundle.module.url( @@ -21,19 +22,11 @@ class ConvertSubcommandTests: XCTestCase { func testOptionsValidation() throws { // create source bundle directory - let sourceURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString).appendingPathExtension("documentation") - try FileManager.default.createDirectory(at: sourceURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: sourceURL) - } + let sourceURL = try createTemporaryDirectory(named: "documentation") try "".write(to: sourceURL.appendingPathComponent("Info.plist"), atomically: true, encoding: .utf8) // create template dir - let rendererTemplateDirectory = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: rendererTemplateDirectory, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: rendererTemplateDirectory) - } + let rendererTemplateDirectory = try createTemporaryDirectory() try "".write(to: rendererTemplateDirectory.appendingPathComponent("index.html"), atomically: true, encoding: .utf8) // Tests a single input. @@ -84,11 +77,11 @@ class ConvertSubcommandTests: XCTestCase { // Test default template do { unsetenv(TemplateOption.environmentVariableKey) - let tempDir = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - let doccExecutableLocation = tempDir + let tempFolder = try createTemporaryDirectory() + let doccExecutableLocation = tempFolder .appendingPathComponent("bin") .appendingPathComponent("docc-executable-name") - let defaultTemplateDir = tempDir + let defaultTemplateDir = tempFolder .appendingPathComponent("share") .appendingPathComponent("docc") .appendingPathComponent("render", isDirectory: true) diff --git a/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ErrorMessageTests.swift b/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ErrorMessageTests.swift index 98e64c00ee..e5ea02cb8e 100644 --- a/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ErrorMessageTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ErrorMessageTests.swift @@ -16,19 +16,11 @@ class ErrorMessageTests: XCTestCase { func testInvalidParameterMessageError() throws { // create source bundle directory - let sourceURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString).appendingPathExtension("documentation") - try FileManager.default.createDirectory(at: sourceURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: sourceURL) - } + let sourceURL = try createTemporaryDirectory(named: "documentation") try "".write(to: sourceURL.appendingPathComponent("Info.plist"), atomically: true, encoding: .utf8) // create renderer template directory - let rendererDirectory = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: rendererDirectory, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: rendererDirectory) - } + let rendererDirectory = try createTemporaryDirectory() try "".write(to: rendererDirectory.appendingPathComponent("index.html"), atomically: true, encoding: .utf8) do { diff --git a/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/PreviewSubcommandTests.swift b/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/PreviewSubcommandTests.swift index faed8227a5..051a369d0d 100644 --- a/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/PreviewSubcommandTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/PreviewSubcommandTests.swift @@ -17,25 +17,16 @@ class PreviewSubcommandTests: XCTestCase { forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! // Create HTML template dir. - let templateDir = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: templateDir, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: templateDir) - } + let templateDir = try createTemporaryDirectory() try "".write(to: templateDir.appendingPathComponent("index.html"), atomically: true, encoding: .utf8) + let tempURL = try createTemporaryDirectory() // Create Test TLS Certificate File - let testTLSCertificate = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("testCert.pem") - defer { - try? FileManager.default.removeItem(at: testTLSCertificate) - } + let testTLSCertificate = tempURL.appendingPathComponent("testCert.pem") try "".write(to: testTLSCertificate, atomically: true, encoding: .utf8) // Create Test TLS Key File - let testTLSKey = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("testCert.pem") - defer { - try? FileManager.default.removeItem(at: testTLSKey) - } + let testTLSKey = tempURL.appendingPathComponent("testCert.pem") try "".write(to: testTLSKey, atomically: true, encoding: .utf8) // Tests a single input. @@ -57,11 +48,11 @@ class PreviewSubcommandTests: XCTestCase { // Test default template do { unsetenv(TemplateOption.environmentVariableKey) - let tempDir = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - let doccExecutableLocation = tempDir + let tempFolder = try createTemporaryDirectory() + let doccExecutableLocation = tempFolder .appendingPathComponent("bin") .appendingPathComponent("docc-executable-name") - let defaultTemplateDir = tempDir + let defaultTemplateDir = tempFolder .appendingPathComponent("share") .appendingPathComponent("docc") .appendingPathComponent("render", isDirectory: true) @@ -72,9 +63,6 @@ class PreviewSubcommandTests: XCTestCase { TemplateOption.doccExecutableLocation = originalDoccExecutableLocation } try FileManager.default.createDirectory(at: defaultTemplateDir, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: defaultTemplateDir) - } try "".write(to: defaultTemplateDir.appendingPathComponent("index.html"), atomically: true, encoding: .utf8) let preview = try Docc.Preview.parse([ diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionIndexerTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionIndexerTests.swift index 151c9ecadb..be9a224214 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionIndexerTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionIndexerTests.swift @@ -21,9 +21,7 @@ class ConvertActionIndexerTests: XCTestCase { forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! // Create temo folder. - let url = URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString)) - try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: url) } + let url = try createTemporaryDirectory() // Copy TestBundle into a temp folder let testBundleURL = url.appendingPathComponent("TestBundle.docc") diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionStaticHostableTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionStaticHostableTests.swift index 05f75401f8..96e0b4d48e 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionStaticHostableTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionStaticHostableTests.swift @@ -12,28 +12,22 @@ import XCTest import Foundation @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities class ConvertActionStaticHostableTests: StaticHostingBaseTests { /// Creates a DocC archive and then archives it with options to produce static content which is then validated. func testConvertActionStaticHostableTestOutput() throws { let bundleURL = Bundle.module.url(forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let fileManager = FileManager.default - try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { try? fileManager.removeItem(at: targetURL) } - let targetBundleURL = targetURL.appendingPathComponent("Result.doccarchive") - defer { try? fileManager.removeItem(at: targetBundleURL) } - - let testTemplateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let testTemplateURL = try createTemporaryDirectory().appendingPathComponent("testTemplate") let templateFolder = Folder.testHTMLTemplateDirectory try templateFolder.write(to: testTemplateURL) - defer { try? fileManager.removeItem(at: testTemplateURL) } - let basePath = "test/folder" let indexHTML = Folder.testHTMLTemplate(basePath: "test/folder") @@ -47,12 +41,12 @@ class ConvertActionStaticHostableTests: StaticHostingBaseTests { emitDigest: false, currentPlatforms: nil, transformForStaticHosting: true, - hostingBasePath: basePath + hostingBasePath: basePath, + temporaryDirectory: try createTemporaryDirectory() ) _ = try action.perform(logHandle: .standardOutput) - // Test the content of the output folder. var expectedContent = ["data", "documentation", "tutorials", "downloads", "images", "metadata.json" ,"videos", "index.html"] expectedContent += templateFolder.content.filter { $0 is Folder }.map{ $0.name } diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift index 3008d736fa..5be793cd08 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift @@ -13,6 +13,7 @@ import Foundation @testable import SwiftDocC @testable import SwiftDocCUtilities import Markdown +import SwiftDocCTestUtilities class ConvertActionTests: XCTestCase { #if !os(iOS) @@ -89,7 +90,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) // Verify that the following files and folder exist at the output location @@ -135,7 +137,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) // Verify that the following files and folder exist at the output location @@ -193,7 +196,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) // Verify that the following files and folder exist at the output location @@ -226,7 +230,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) // Verify that the following files and folder exist at the output location @@ -258,7 +263,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) XCTAssertEqual(result.problems.count, 0) } @@ -291,6 +297,7 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), bundleDiscoveryOptions: BundleDiscoveryOptions( infoPlistFallbacks: infoPlistFallbacks, additionalSymbolGraphFiles: [URL(fileURLWithPath: "/Not-a-doc-bundle/MyKit.symbols.json")] @@ -354,6 +361,7 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), bundleDiscoveryOptions: BundleDiscoveryOptions( infoPlistFallbacks: infoPlistFallbacks, additionalSymbolGraphFiles: [URL(fileURLWithPath: "/Not-a-doc-bundle/MyKit.symbols.json")] @@ -396,7 +404,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let targetURL = target.absoluteURL.appendingPathComponent("output") @@ -432,7 +441,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let targetURL = target.absoluteURL.appendingPathComponent("target").appendingPathComponent("output") @@ -460,7 +470,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) // Verify that the following files and folder exist at the output location @@ -498,7 +509,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .none) // Construct the URLs for the produced render json: @@ -567,7 +579,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .none) // Construct the URLs for the produced render json: @@ -654,7 +667,8 @@ class ConvertActionTests: XCTestCase { emitDigest: true, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) // Verify that the following files and folder exist at the output location @@ -711,6 +725,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: testDataProvider, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), diagnosticLevel: "hint") // report all errors during the test let result = try action.perform(logHandle: .standardOutput) @@ -791,6 +806,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: testDataProvider, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), diagnosticLevel: "hint") // report all errors during the test let result = try action.perform(logHandle: .standardOutput) @@ -875,7 +891,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) XCTAssertFalse( @@ -904,7 +921,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) XCTAssert( @@ -942,7 +960,8 @@ class ConvertActionTests: XCTestCase { emitDigest: true, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) // Verify that the following files and folder exist at the output location @@ -1031,7 +1050,8 @@ class ConvertActionTests: XCTestCase { emitDigest: true, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) // Because the page order isn't deterministic, we create the indexing records and linkable entities in the same order as the pages. @@ -1236,7 +1256,8 @@ class ConvertActionTests: XCTestCase { emitDigest: true, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) // Because the page order isn't deterministic, we create the indexing records and linkable entities in the same order as the pages. @@ -1391,7 +1412,8 @@ class ConvertActionTests: XCTestCase { emitDigest: true, // emit digest files currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) XCTAssertTrue(testDataProvider.fileExists(atPath: result.outputs[0].appendingPathComponent("assets.json").path)) @@ -1415,7 +1437,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, // don't emit digest files currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) let result = try action.perform(logHandle: .standardOutput) XCTAssertFalse(testDataProvider.fileExists(atPath: result.outputs[0].appendingPathComponent("assets.json").path)) @@ -1448,6 +1471,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: testDataProvider, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), documentationCoverageOptions: .noCoverage) let result = try action.perform(logHandle: .standardOutput) @@ -1470,6 +1494,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: testDataProvider, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), documentationCoverageOptions: DocumentationCoverageOptions(level: .brief)) let result = try action.perform(logHandle: .standardOutput) @@ -1492,6 +1517,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: testDataProvider, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), documentationCoverageOptions: DocumentationCoverageOptions(level: .detailed)) let result = try action.perform(logHandle: .standardOutput) @@ -1526,7 +1552,8 @@ class ConvertActionTests: XCTestCase { "platform2": PlatformVersion(.init(11, 12, 13), beta: false), ], dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) XCTAssertEqual(action.context.externalMetadata.currentPlatforms, [ "platform1" : PlatformVersion(.init(10, 11, 12), beta: false), @@ -1556,6 +1583,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: testDataProvider, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), diagnosticEngine: engine) let result = try action.perform(logHandle: .standardOutput) XCTAssertFalse(result.didEncounterError) @@ -1620,7 +1648,8 @@ class ConvertActionTests: XCTestCase { emitDigest: emitDigest, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) action.converter.batchNodeCount = batchSize @@ -1699,7 +1728,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testFileSystem, - fileManager: testFileSystem + fileManager: testFileSystem, + temporaryDirectory: createTemporaryDirectory() ) _ = try action.perform(logHandle: .none) @@ -1759,15 +1789,9 @@ class ConvertActionTests: XCTestCase { // The navigator index needs to test with the real file manager let bundleURL = Bundle.module.url(forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - - let fileManager = FileManager.default - try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { try? fileManager.removeItem(at: targetURL) } - - let templateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() + let templateURL = try createTemporaryDirectory().appendingPathComponent("template") try Folder.emptyHTMLTemplateDirectory.write(to: templateURL) - defer { try? fileManager.removeItem(at: templateURL) } // Convert the documentation and create an index @@ -1779,7 +1803,8 @@ class ConvertActionTests: XCTestCase { htmlTemplateDirectory: templateURL, emitDigest: false, currentPlatforms: nil, - buildIndex: true // Create an index + buildIndex: true, + temporaryDirectory: createTemporaryDirectory() // Create an index ) _ = try action.perform(logHandle: .standardOutput) @@ -1788,7 +1813,7 @@ class ConvertActionTests: XCTestCase { let indexFromConvertAction = try NavigatorIndex(url: indexURL) XCTAssertEqual(indexFromConvertAction.count, 37) - try fileManager.removeItem(at: indexURL) + try FileManager.default.removeItem(at: indexURL) // Run just the index command over the built documentation @@ -1815,17 +1840,7 @@ class ConvertActionTests: XCTestCase { ]) // The navigator index needs to test with the real File Manager - let testTemporaryDirectory = FileManager.default.temporaryDirectory.appendingPathComponent( - "\(#function)-\(UUID())" - ) - try FileManager.default.createDirectory( - at: testTemporaryDirectory, - withIntermediateDirectories: true, - attributes: nil - ) - defer { - try? FileManager.default.removeItem(at: testTemporaryDirectory) - } + let testTemporaryDirectory = try createTemporaryDirectory() let bundleDirectory = testTemporaryDirectory.appendingPathComponent( bundle.name, @@ -1846,7 +1861,8 @@ class ConvertActionTests: XCTestCase { htmlTemplateDirectory: nil, emitDigest: false, currentPlatforms: nil, - buildIndex: true + buildIndex: true, + temporaryDirectory: createTemporaryDirectory() ) enableFeatureFlag(\.isExperimentalObjectiveCSupportEnabled) @@ -1881,18 +1897,7 @@ class ConvertActionTests: XCTestCase { enableFeatureFlag(\.isExperimentalObjectiveCSupportEnabled) // The navigator index needs to test with the real File Manager - let temporaryTestOutputDirectory = FileManager.default.temporaryDirectory.appendingPathComponent( - "\(#function)-\(UUID())" - ) - try FileManager.default.createDirectory( - at: temporaryTestOutputDirectory, - withIntermediateDirectories: true, - attributes: nil - ) - - defer { - try? FileManager.default.removeItem(at: temporaryTestOutputDirectory) - } + let temporaryTestOutputDirectory = try createTemporaryDirectory() let bundleDirectory = try XCTUnwrap( Bundle.module.url( @@ -1911,7 +1916,8 @@ class ConvertActionTests: XCTestCase { htmlTemplateDirectory: nil, emitDigest: false, currentPlatforms: nil, - buildIndex: true + buildIndex: true, + temporaryDirectory: createTemporaryDirectory() ) _ = try action.perform(logHandle: .none) @@ -2061,6 +2067,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: testDataProvider, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), diagnosticLevel: "error", diagnosticEngine: engine ) @@ -2098,6 +2105,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: testDataProvider, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), diagnosticLevel: "error", diagnosticEngine: engine ) @@ -2136,6 +2144,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: testDataProvider, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), diagnosticLevel: "error" ) XCTAssertThrowsError(try action.performAndHandleResult()) { error in @@ -2166,6 +2175,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: testDataProvider, fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory(), inheritDocs: flag) XCTAssertEqual(action.context.externalMetadata.inheritDocs, flag) } @@ -2180,7 +2190,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider) + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory()) XCTAssertEqual(action.context.externalMetadata.inheritDocs, false) } @@ -2206,7 +2217,8 @@ class ConvertActionTests: XCTestCase { emitDigest: true, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory() ) XCTAssertThrowsError(try action.performAndHandleResult(), "The test bundle should have thrown an error about an incomplete symbol graph file") @@ -2236,7 +2248,8 @@ class ConvertActionTests: XCTestCase { emitDigest: true, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory() ) try action.performAndHandleResult() @@ -2272,7 +2285,8 @@ class ConvertActionTests: XCTestCase { emitDigest: false, currentPlatforms: nil, dataProvider: testDataProvider, - fileManager: testDataProvider + fileManager: testDataProvider, + temporaryDirectory: createTemporaryDirectory() ) let result = try action.perform(logHandle: .standardOutput) @@ -2316,10 +2330,7 @@ class ConvertActionTests: XCTestCase { footer, ]) - let tempURL = URL(fileURLWithPath: NSTemporaryDirectory()) - .appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) - defer { try? FileManager.default.removeItem(at: tempURL) } + let tempURL = try createTemporaryDirectory() let targetURL = tempURL.appendingPathComponent("target", isDirectory: true) let bundleURL = try bundle.write(inside: tempURL) @@ -2337,6 +2348,7 @@ class ConvertActionTests: XCTestCase { currentPlatforms: nil, dataProvider: dataProvider, fileManager: FileManager.default, + temporaryDirectory: createTemporaryDirectory(), experimentalEnableCustomTemplates: true ) let result = try action.perform(logHandle: .standardOutput) @@ -2434,8 +2446,8 @@ extension Folder { if fileURL.lastPathComponent == "Info.plist", let infoPlistData = FileManager.default.contents(atPath: fileURL.path), let infoPlist = try? PropertyListSerialization.propertyList(from: infoPlistData, options: [], format: nil) as? [String: Any], - let displayName = infoPlist[InfoPlist.Content.CodingKeys.displayName.rawValue] as? String, - let identifier = infoPlist[InfoPlist.Content.CodingKeys.identifier.rawValue] as? String { + let displayName = infoPlist["CFBundleDisplayName"] as? String, + let identifier = infoPlist["CFBundleIdentifier"] as? String { content.append(InfoPlist(displayName: displayName, identifier: identifier)) } else { content.append(CopyOfFile(original: fileURL, newName: fileURL.lastPathComponent)) diff --git a/Tests/SwiftDocCUtilitiesTests/DirectoryMonitorTests.swift b/Tests/SwiftDocCUtilitiesTests/DirectoryMonitorTests.swift index 004c51879d..07a9f9c96d 100644 --- a/Tests/SwiftDocCUtilitiesTests/DirectoryMonitorTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/DirectoryMonitorTests.swift @@ -121,12 +121,8 @@ class DirectoryMonitorTests: XCTestCase { #if !os(Linux) && !os(Android) // Create temp folder & sub-folder. - let tempFolderURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - let tempSubfolderURL = tempFolderURL.appendingPathComponent("subfolder") - try FileManager.default.createDirectory(at: tempSubfolderURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: tempFolderURL) - } + let tempSubfolderURL = try createTemporaryDirectory(named: "subfolder") + let tempFolderURL = tempSubfolderURL.deletingLastPathComponent() // A file URL to update. let updateURL = tempSubfolderURL.appendingPathComponent("test.txt") @@ -174,12 +170,8 @@ class DirectoryMonitorTests: XCTestCase { #if !os(Linux) && !os(Android) // Create temp folder & sub-folder. - let tempFolderURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - let tempSubfolderURL = tempFolderURL.appendingPathComponent("subfolder") - try FileManager.default.createDirectory(at: tempSubfolderURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: tempFolderURL) - } + let tempSubfolderURL = try createTemporaryDirectory(named: "subfolder") + let tempFolderURL = tempSubfolderURL.deletingLastPathComponent() // 1) Test that creating a hidden file inside the tree will not trigger an update. try monitorNoUpdates(url: tempFolderURL, testBlock: { @@ -211,12 +203,8 @@ class DirectoryMonitorTests: XCTestCase { #if !os(Linux) && !os(Android) // Create temp folder & sub-folder. - let tempFolderURL = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - let tempSubfolderURL = tempFolderURL.appendingPathComponent("subfolder") - try FileManager.default.createDirectory(at: tempSubfolderURL, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: tempFolderURL) - } + let tempSubfolderURL = try createTemporaryDirectory(named: "subfolder") + let tempFolderURL = tempSubfolderURL.deletingLastPathComponent() // A file URL to update. let updateURL = tempSubfolderURL.appendingPathComponent("test.txt") diff --git a/Tests/SwiftDocCUtilitiesTests/FolderStructure.swift b/Tests/SwiftDocCUtilitiesTests/FolderStructure.swift index e08b9dcab8..c408fbf751 100644 --- a/Tests/SwiftDocCUtilitiesTests/FolderStructure.swift +++ b/Tests/SwiftDocCUtilitiesTests/FolderStructure.swift @@ -11,6 +11,7 @@ @testable import SwiftDocC @testable import SwiftDocCUtilities import XCTest +import SwiftDocCTestUtilities /* This file contains a test helper API for working with folder hierarchies, with the ability to: @@ -69,10 +70,10 @@ extension InfoPlist: AssertableFile { } let infoPlist = try PropertyListSerialization.propertyList(from: infoPlistData, options: [], format: nil) as? [String: String] - let displayName = infoPlist?[Content.CodingKeys.displayName.rawValue] - let identifier = infoPlist?[Content.CodingKeys.identifier.rawValue] - let versionString = infoPlist?[Content.CodingKeys.versionString.rawValue] - let developmentRegion = infoPlist?[Content.CodingKeys.developmentRegion.rawValue] + let displayName = infoPlist?["CFBundleIdentifier"] + let identifier = infoPlist?["CFBundleVersion"] + let versionString = infoPlist?["CFBundleDevelopmentRegion"] + let developmentRegion = infoPlist?["CFBundleDisplayName"] XCTAssert(displayName == content.displayName && identifier == content.identifier && versionString == content.versionString && developmentRegion == content.developmentRegion, "File '\(name)' should contain the correct information.", file: (file), line: line) diff --git a/Tests/SwiftDocCUtilitiesTests/FolderStructureTests.swift b/Tests/SwiftDocCUtilitiesTests/FolderStructureTests.swift index 43136c334e..8a9c6ad396 100644 --- a/Tests/SwiftDocCUtilitiesTests/FolderStructureTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/FolderStructureTests.swift @@ -10,6 +10,7 @@ import XCTest @testable import SwiftDocC +import SwiftDocCTestUtilities class FolderStructureTests: XCTestCase { @@ -105,23 +106,4 @@ class FolderStructureTests: XCTestCase { XCTAssertEqual(try FileManager.default.contentsOfDirectory(atPath: lowercaseCopyURL.path), ["lower"]) } - - // Workaround that addTeardownBlock doesn't exist in swift-corelibs-xctest - - private var tempFilesToRemove: [URL] = [] - - override func tearDown() { - for url in tempFilesToRemove { - try? FileManager.default.removeItem(at: url) - } - tempFilesToRemove.removeAll() - super.tearDown() - } - - func createTemporaryDirectory() throws -> URL { - let url = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil) - tempFilesToRemove.append(url) - return url - } } diff --git a/Tests/SwiftDocCUtilitiesTests/HTMLTemplateDirectory.swift b/Tests/SwiftDocCUtilitiesTests/HTMLTemplateDirectory.swift index 118eb13476..09ee4a1797 100644 --- a/Tests/SwiftDocCUtilitiesTests/HTMLTemplateDirectory.swift +++ b/Tests/SwiftDocCUtilitiesTests/HTMLTemplateDirectory.swift @@ -10,6 +10,7 @@ import Foundation @testable import SwiftDocC +import SwiftDocCTestUtilities /// A folder that represents a fake html-build directory for testing. extension Folder { diff --git a/Tests/SwiftDocCUtilitiesTests/IndexActionTests.swift b/Tests/SwiftDocCUtilitiesTests/IndexActionTests.swift index 1e707ba3f4..5af4d7c07f 100644 --- a/Tests/SwiftDocCUtilitiesTests/IndexActionTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/IndexActionTests.swift @@ -13,6 +13,7 @@ import Foundation @testable import SwiftDocC @testable import SwiftDocCUtilities import Markdown +import SwiftDocCTestUtilities class IndexActionTests: XCTestCase { #if !os(iOS) @@ -20,15 +21,9 @@ class IndexActionTests: XCTestCase { // Convert a test bundle as input for the IndexAction let bundleURL = Bundle.module.url(forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - - let fileManager = FileManager.default - try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { try? fileManager.removeItem(at: targetURL) } - - let templateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() + let templateURL = try createTemporaryDirectory().appendingPathComponent("template") try Folder.emptyHTMLTemplateDirectory.write(to: templateURL) - defer { try? fileManager.removeItem(at: templateURL) } let targetBundleURL = targetURL.appendingPathComponent("Result.builtdocs") @@ -39,7 +34,8 @@ class IndexActionTests: XCTestCase { targetDirectory: targetBundleURL, htmlTemplateDirectory: templateURL, emitDigest: false, - currentPlatforms: nil + currentPlatforms: nil, + temporaryDirectory: createTemporaryDirectory() ) _ = try action.perform(logHandle: .standardOutput) diff --git a/Tests/SwiftDocCUtilitiesTests/OutOfProcessReferenceResolverTests.swift b/Tests/SwiftDocCUtilitiesTests/OutOfProcessReferenceResolverTests.swift index fdebd58ba7..7f03037ba7 100644 --- a/Tests/SwiftDocCUtilitiesTests/OutOfProcessReferenceResolverTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/OutOfProcessReferenceResolverTests.swift @@ -13,16 +13,13 @@ import Foundation import SymbolKit @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities class OutOfProcessReferenceResolverTests: XCTestCase { func testInitializationProcess() throws { #if os(macOS) - let temporaryFolder = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: temporaryFolder, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: temporaryFolder) - } + let temporaryFolder = try createTemporaryDirectory() let executableLocation = temporaryFolder.appendingPathComponent("link-resolver-executable") // When the executable file doesn't exist @@ -120,11 +117,7 @@ class OutOfProcessReferenceResolverTests: XCTestCase { func testResolvingTopicLinkProcess() throws { #if os(macOS) try assertResolvesTopicLink(makeResolver: { testMetadata in - let temporaryFolder = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: temporaryFolder, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: temporaryFolder) - } + let temporaryFolder = try createTemporaryDirectory() let executableLocation = temporaryFolder.appendingPathComponent("link-resolver-executable") let encodedMetadata = try String(data: JSONEncoder().encode(testMetadata), encoding: .utf8)! @@ -256,11 +249,7 @@ class OutOfProcessReferenceResolverTests: XCTestCase { func testResolvingSymbolProcess() throws { #if os(macOS) try assertResolvesSymbol(makeResolver: { testMetadata in - let temporaryFolder = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: temporaryFolder, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: temporaryFolder) - } + let temporaryFolder = try createTemporaryDirectory() let executableLocation = temporaryFolder.appendingPathComponent("link-resolver-executable") let encodedMetadata = try String(data: JSONEncoder().encode(testMetadata), encoding: .utf8)! @@ -327,11 +316,7 @@ class OutOfProcessReferenceResolverTests: XCTestCase { func testForwardsErrorOutputProcess() throws { #if os(macOS) - let temporaryFolder = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: temporaryFolder, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: temporaryFolder) - } + let temporaryFolder = try createTemporaryDirectory() let executableLocation = temporaryFolder.appendingPathComponent("link-resolver-executable") try """ @@ -370,11 +355,7 @@ class OutOfProcessReferenceResolverTests: XCTestCase { func testForwardsResolverErrorsProcess() throws { #if os(macOS) - let temporaryFolder = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: temporaryFolder, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: temporaryFolder) - } + let temporaryFolder = try createTemporaryDirectory() let executableLocation = temporaryFolder.appendingPathComponent("link-resolver-executable") try """ @@ -504,11 +485,7 @@ class OutOfProcessReferenceResolverTests: XCTestCase { func testErrorWhenReceivingBundleIdentifierTwiceProcess() throws { #if os(macOS) - let temporaryFolder = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: temporaryFolder, withIntermediateDirectories: true, attributes: nil) - defer { - try? FileManager.default.removeItem(at: temporaryFolder) - } + let temporaryFolder = try createTemporaryDirectory() let executableLocation = temporaryFolder.appendingPathComponent("link-resolver-executable") try """ diff --git a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift index 4e14896bb7..731446b391 100644 --- a/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/PreviewActionIntegrationTests.swift @@ -11,6 +11,7 @@ import XCTest @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities class PreviewActionIntegrationTests: XCTestCase { func json(contentsOf url: URL) throws -> [String: Any] { @@ -70,9 +71,6 @@ class PreviewActionIntegrationTests: XCTestCase { return (sourceURL: sourceURL, outputURL: outputURL, templateURL: templateURL) } -/* - FIXME: This test can fail when run in parallel so it is temporarily disabled (rdar://81524725). - /// Test the fix for . func testWatchRecoversAfterConversionErrors() throws { #if os(macOS) @@ -80,12 +78,10 @@ class PreviewActionIntegrationTests: XCTestCase { let source = createMinimalDocsBundle() let (sourceURL, outputURL, templateURL) = try createPreviewSetup(source: source) - let sourceOverviewURL = sourceURL.appendingPathComponent("Resources") - .appendingPathComponent("Overview.tutorial") - let logStorage = LogHandle.LogStorage() var logHandle = LogHandle.memory(logStorage) + let convertActionTempDirectory = try createTemporaryDirectory() let createConvertAction = { try ConvertAction( documentationBundleURL: sourceURL, @@ -95,7 +91,8 @@ class PreviewActionIntegrationTests: XCTestCase { htmlTemplateDirectory: templateURL, emitDigest: false, currentPlatforms: nil, - fileManager: FileManager.default) + fileManager: FileManager.default, + temporaryDirectory: convertActionTempDirectory) } guard let preview = try? PreviewAction( @@ -109,7 +106,7 @@ class PreviewActionIntegrationTests: XCTestCase { return } - let socketURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString).appendingPathExtension("sock") + let socketURL = try createTemporaryDirectory().appendingPathComponent("sock") preview.bindServerToSocketPath = socketURL.path // The technology output file URL @@ -180,14 +177,14 @@ class PreviewActionIntegrationTests: XCTestCase { XCTAssertEqual(initialIntroTitle, "Technology X") + let invalidJSONSymbolGraphURL = sourceURL.appendingPathComponent("invalid-incomplete-data.symbols.json") + // Start watching the source and detect failed conversion. do { let outputExpectation = asyncLogExpectation(log: logStorage, description: "Did produce output") { $0.contains("Compilation failed") } - // Triger a watch update. - try String(contentsOf: sourceOverviewURL) - .replacingOccurrences(of: "title: \"Technology X\"", with: "ti!!!!!!tle: \"Technology X\"") - .write(to: sourceOverviewURL, atomically: true, encoding: .utf8) + // this is invalid JSON and will result in an error + try "{".write(to: invalidJSONSymbolGraphURL, atomically: true, encoding: .utf8) // Wait for watch to produce output. wait(for: [outputExpectation], timeout: 20.0) @@ -197,9 +194,7 @@ class PreviewActionIntegrationTests: XCTestCase { do { let outputExpectation = asyncLogExpectation(log: logStorage, description: "Did finish conversion") { $0.contains("Done") } - try String(contentsOf: sourceOverviewURL) - .replacingOccurrences(of: "ti!!!!!!tle: \"Technology X\"", with: "title: \"Technology X\"") - .write(to: sourceOverviewURL, atomically: true, encoding: .utf8) + try FileManager.default.removeItem(at: invalidJSONSymbolGraphURL) // Wait for watch to produce output. wait(for: [outputExpectation], timeout: 20.0) @@ -223,7 +218,6 @@ class PreviewActionIntegrationTests: XCTestCase { try FileManager.default.removeItem(at: templateURL) #endif } -*/ class MemoryOutputChecker { init(storage: LogHandle.LogStorage, expectation: XCTestExpectation, condition: @escaping (String)->Bool) { @@ -237,7 +231,7 @@ class PreviewActionIntegrationTests: XCTestCase { let condition: (String)->Bool } - /// Helper class to fulfill an expecation when given condition is met. + /// Helper class to fulfill an expectation when given condition is met. class OutputChecker { init(fileURL: URL, expectation: XCTestExpectation, condition: @escaping (String)->Bool) { self.url = fileURL @@ -250,7 +244,7 @@ class PreviewActionIntegrationTests: XCTestCase { let condition: (String)->Bool } - /// Check the contents of the log file for the expectatation. + /// Check the contents of the log file for the expectation. func checkOutput(timer: Timer) { if let checker = timer.userInfo as? OutputChecker { if let data = try? Data(contentsOf: checker.url), @@ -291,6 +285,7 @@ class PreviewActionIntegrationTests: XCTestCase { let engine = DiagnosticEngine() + let convertActionTempDirectory = try createTemporaryDirectory() let createConvertAction = { try ConvertAction( documentationBundleURL: sourceURL, @@ -301,6 +296,7 @@ class PreviewActionIntegrationTests: XCTestCase { emitDigest: false, currentPlatforms: nil, fileManager: FileManager.default, + temporaryDirectory: convertActionTempDirectory, diagnosticEngine: engine) } @@ -361,6 +357,7 @@ class PreviewActionIntegrationTests: XCTestCase { let logStorage = LogHandle.LogStorage() let logHandle = LogHandle.memory(logStorage) + let convertActionTempDirectory = try createTemporaryDirectory() let createConvertAction = { try ConvertAction( documentationBundleURL: sourceURL, @@ -370,7 +367,8 @@ class PreviewActionIntegrationTests: XCTestCase { htmlTemplateDirectory: templateURL, emitDigest: false, currentPlatforms: nil, - fileManager: FileManager.default) + fileManager: FileManager.default, + temporaryDirectory: convertActionTempDirectory) } guard let preview = try? PreviewAction( @@ -431,6 +429,7 @@ class PreviewActionIntegrationTests: XCTestCase { var convertFuture: () -> Void = {} + let convertActionTempDirectory = try createTemporaryDirectory() /// Create the convert action and store it let createConvertAction = { () -> ConvertAction in var convertAction = try ConvertAction( @@ -441,7 +440,8 @@ class PreviewActionIntegrationTests: XCTestCase { htmlTemplateDirectory: templateURL, emitDigest: false, currentPlatforms: nil, - fileManager: FileManager.default) + fileManager: FileManager.default, + temporaryDirectory: convertActionTempDirectory) // Inject a future to control how long the conversion takes convertAction.willPerformFuture = convertFuture @@ -460,7 +460,7 @@ class PreviewActionIntegrationTests: XCTestCase { return } - let socketURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString).appendingPathExtension("sock") + let socketURL = try createTemporaryDirectory().appendingPathComponent("sock") preview.bindServerToSocketPath = socketURL.path // Start watching the source and get the initial (successful) state. @@ -540,10 +540,6 @@ class PreviewActionIntegrationTests: XCTestCase { // MARK: - - // Workaround that addTeardownBlock doesn't exist in swift-corelibs-xctest - - private static var tempFilesToRemove: [URL] = [] - override static func setUp() { super.setUp() PreviewAction.allowConcurrentPreviews = true @@ -551,21 +547,6 @@ class PreviewActionIntegrationTests: XCTestCase { override static func tearDown() { PreviewAction.allowConcurrentPreviews = false - for url in tempFilesToRemove { - try? FileManager.default.removeItem(at: url) - } - tempFilesToRemove.removeAll() super.tearDown() } - - func createTemporaryDirectory() throws -> URL { - // We append "-test" here because the convert action uses the same logic - // to create its temporary directory and we don't want to rely on - // this folder already existing - let url = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()) - .appendingPathComponent("\(ProcessInfo.processInfo.globallyUniqueString)-test") - try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil) - Self.tempFilesToRemove.append(url) - return url - } } diff --git a/Tests/SwiftDocCUtilitiesTests/PreviewServer/PreviewHTTPHandlerTests.swift b/Tests/SwiftDocCUtilitiesTests/PreviewServer/PreviewHTTPHandlerTests.swift index 8c05689ad2..8f3d478128 100644 --- a/Tests/SwiftDocCUtilitiesTests/PreviewServer/PreviewHTTPHandlerTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/PreviewServer/PreviewHTTPHandlerTests.swift @@ -12,6 +12,7 @@ import Foundation import XCTest @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities import NIO import NIOHTTP1 @@ -21,16 +22,15 @@ class PreviewHTTPHandlerTests: XCTestCase { /// Tests the three different responses we offer: static file, default, and error. func testPreviewHandler() throws { - let tempDir = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ TextFile(name: "index.html", utf8Content: "index"), Folder(name: "css", content: [ TextFile(name: "test.css", utf8Content: "css"), ]) ]) - try tempDir.write(to: URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString))) let channel = EmbeddedChannel() - let channelHandler = PreviewHTTPHandler(fileIO: fileIO, rootURL: tempDir.url) + let channelHandler = PreviewHTTPHandler(fileIO: fileIO, rootURL: tempFolderURL) let response = Response() @@ -83,13 +83,12 @@ class PreviewHTTPHandlerTests: XCTestCase { } func testPreviewAuthHandler() throws { - let tempDir = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ TextFile(name: "index.html", utf8Content: "index"), Folder(name: "css", content: [ TextFile(name: "test.css", utf8Content: "css"), ]) ]) - try tempDir.write(to: URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString))) let channel = EmbeddedChannel() defer { @@ -97,7 +96,7 @@ class PreviewHTTPHandlerTests: XCTestCase { _ = try? channel.finish() } - let channelHandler = PreviewHTTPHandler(fileIO: fileIO, rootURL: tempDir.url, credentials: (user: "user", pass: "pass")) + let channelHandler = PreviewHTTPHandler(fileIO: fileIO, rootURL: tempFolderURL, credentials: (user: "user", pass: "pass")) let response = Response() diff --git a/Tests/SwiftDocCUtilitiesTests/PreviewServer/PreviewServerTests.swift b/Tests/SwiftDocCUtilitiesTests/PreviewServer/PreviewServerTests.swift index ed7a982e33..b4c4b4050a 100644 --- a/Tests/SwiftDocCUtilitiesTests/PreviewServer/PreviewServerTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/PreviewServer/PreviewServerTests.swift @@ -13,6 +13,7 @@ import Foundation @testable import SwiftDocCUtilities @testable import SwiftDocC +import SwiftDocCTestUtilities @testable import NIO @testable import NIOHTTP1 @@ -25,18 +26,27 @@ import Foundation // class PreviewServerTests: XCTestCase { class PreviewServerTests { + func createTemporaryDirectory( + fileManager: FileManager = .default + ) throws -> URL { + fatalError("This test is disabled by not conforming to XCTestCase. This helper is added here to make the code compile. This should never be called.") + } + + public func createTempFolder(content: [File]) throws -> URL { + fatalError("This test is disabled by not conforming to XCTestCase. This helper is added here to make the code compile. This should never be called.") + } + func testPreviewServerBeforeStarted() throws { // Create test content - let tempFolder = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ TextFile(name: "index.html", utf8Content: "index"), ]) - try tempFolder.write(to: URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString))) - let socketURL = URL(fileURLWithPath: FileManager.default.temporaryDirectory.path).appendingPathComponent(UUID().uuidString).appendingPathExtension("sock") + let socketURL = try createTemporaryDirectory().appendingPathComponent("sock") // Run test server var log = LogHandle.none - let server = try PreviewServer(contentURL: tempFolder.url, bindTo: .socket(path: socketURL.path), username: "username", password: "password", logHandle: &log) + let server = try PreviewServer(contentURL: tempFolderURL, bindTo: .socket(path: socketURL.path), username: "username", password: "password", logHandle: &log) // Assert server starts let expectationStarted = AsyncronousExpectation(description: "Server before start") @@ -73,9 +83,9 @@ class PreviewServerTests { XCTAssertEqual(client.handler.statusCode, errorStatusCode, file: (file), line: line) } - private func makeTempFolder() throws -> TempFolder { + private func makeTempFolder() throws -> URL { // Create test content - try TempFolder(content: [ + try createTempFolder(content: [ TextFile(name: "index.html", utf8Content: "index"), TextFile(name: "theme-settings.js", utf8Content: "java script content"), TextFile(name: "theme-settings.json", utf8Content: "JSON content"), @@ -109,14 +119,14 @@ class PreviewServerTests { } func testPreviewServerPaths() throws { - let tempFolder = try makeTempFolder() + let tempFolderURL = try makeTempFolder() // Socket URL - let socketURL = URL(fileURLWithPath: FileManager.default.temporaryDirectory.path).appendingPathComponent(UUID().uuidString).appendingPathExtension("sock") + let socketURL = try createTemporaryDirectory().appendingPathComponent("sock") // Create the server var log = LogHandle.none - let server = try PreviewServer(contentURL: tempFolder.url, bindTo: .socket(path: socketURL.path), username: "username", password: "password", logHandle: &log) + let server = try PreviewServer(contentURL: tempFolderURL, bindTo: .socket(path: socketURL.path), username: "username", password: "password", logHandle: &log) // Start the server let expectationStarted = AsyncronousExpectation(description: "Server before start") @@ -156,14 +166,14 @@ class PreviewServerTests { } func testConcurrentRequests() throws { - let tempFolder = try makeTempFolder() + let tempFolderURL = try makeTempFolder() // Socket URL - let socketURL = URL(fileURLWithPath: FileManager.default.temporaryDirectory.path).appendingPathComponent(UUID().uuidString).appendingPathExtension("sock") + let socketURL = try createTemporaryDirectory().appendingPathComponent("sock") // Create the server var log = LogHandle.none - let server = try PreviewServer(contentURL: tempFolder.url, bindTo: .socket(path: socketURL.path), username: "username", password: "password", logHandle: &log) + let server = try PreviewServer(contentURL: tempFolderURL, bindTo: .socket(path: socketURL.path), username: "username", password: "password", logHandle: &log) // Start the server let expectationStarted = AsyncronousExpectation(description: "Server before start") diff --git a/Tests/SwiftDocCUtilitiesTests/PreviewServer/RequestHandler/DefaultRequestHandlerTests.swift b/Tests/SwiftDocCUtilitiesTests/PreviewServer/RequestHandler/DefaultRequestHandlerTests.swift index 7633da4e2c..e6c6ff70b4 100644 --- a/Tests/SwiftDocCUtilitiesTests/PreviewServer/RequestHandler/DefaultRequestHandlerTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/PreviewServer/RequestHandler/DefaultRequestHandlerTests.swift @@ -12,6 +12,7 @@ import Foundation import XCTest @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities import NIO import NIOHTTP1 @@ -19,14 +20,13 @@ import NIOHTTP1 class DefaultRequestHandlerTests: XCTestCase { func testDefaultHandler() throws { - let tempDir = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ TextFile(name: "index.html", utf8Content: "Hello!"), ]) - try tempDir.write(to: URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString))) // Default handler should be invoked for any non-asset path let request = makeRequestHead(path: "/random-path") - let factory = DefaultRequestHandler(rootURL: tempDir.url) + let factory = DefaultRequestHandler(rootURL: tempFolderURL) let response = try responseWithPipeline(request: request, handler: factory) // Expected content @@ -42,15 +42,14 @@ class DefaultRequestHandlerTests: XCTestCase { } func testDefaultHandlerForExistingPath() throws { - let tempDir = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ TextFile(name: "index.html", utf8Content: "Hello!"), TextFile(name: "existing.html", utf8Content: "Existing!"), ]) - try tempDir.write(to: URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString))) // Default handler should handle even paths that do exist on disc let request = makeRequestHead(path: "/existing.html") - let factory = DefaultRequestHandler(rootURL: tempDir.url) + let factory = DefaultRequestHandler(rootURL: tempFolderURL) let response = try responseWithPipeline(request: request, handler: factory) // Expected content diff --git a/Tests/SwiftDocCUtilitiesTests/PreviewServer/RequestHandler/FileRequestHandlerTests.swift b/Tests/SwiftDocCUtilitiesTests/PreviewServer/RequestHandler/FileRequestHandlerTests.swift index 5bbf359dfd..84774c6bdb 100644 --- a/Tests/SwiftDocCUtilitiesTests/PreviewServer/RequestHandler/FileRequestHandlerTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/PreviewServer/RequestHandler/FileRequestHandlerTests.swift @@ -12,6 +12,7 @@ import Foundation import XCTest @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities import NIO import NIOHTTP1 @@ -31,7 +32,7 @@ class FileRequestHandlerTests: XCTestCase { } func testFileHandlerAssets() throws { - let tempDir = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ Folder(name: "data", content: [ TextFile(name: "test.json", utf8Content: "data"), ]), @@ -64,49 +65,46 @@ class FileRequestHandlerTests: XCTestCase { TextFile(name: "project.zip", utf8Content: "zip"), ]) ]) - try tempDir.write(to: URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString))) - try verifyAsset(root: tempDir.url, path: "/data/test.json", body: "data", type: "application/json") - try verifyAsset(root: tempDir.url, path: "/css/test.css", body: "css", type: "text/css") - try verifyAsset(root: tempDir.url, path: "/js/test.js", body: "js", type: "text/javascript") - try verifyAsset(root: tempDir.url, path: "/fonts/test.otf", body: "font", type: "font/otf") + try verifyAsset(root: tempFolderURL, path: "/data/test.json", body: "data", type: "application/json") + try verifyAsset(root: tempFolderURL, path: "/css/test.css", body: "css", type: "text/css") + try verifyAsset(root: tempFolderURL, path: "/js/test.js", body: "js", type: "text/javascript") + try verifyAsset(root: tempFolderURL, path: "/fonts/test.otf", body: "font", type: "font/otf") // default font type - try verifyAsset(root: tempDir.url, path: "/fonts/test.ttf", body: "ttf", type: "application/octet-stream") - try verifyAsset(root: tempDir.url, path: "/images/image.png", body: "png", type: "image/png") - try verifyAsset(root: tempDir.url, path: "/images/image.gif", body: "gif", type: "image/gif") + try verifyAsset(root: tempFolderURL, path: "/fonts/test.ttf", body: "ttf", type: "application/octet-stream") + try verifyAsset(root: tempFolderURL, path: "/images/image.png", body: "png", type: "image/png") + try verifyAsset(root: tempFolderURL, path: "/images/image.gif", body: "gif", type: "image/gif") // default image type - try verifyAsset(root: tempDir.url, path: "/images/image.jpg", body: "jpg", type: "image/jpeg") - try verifyAsset(root: tempDir.url, path: "/images/logo.svg", body: "svg", type: "image/svg+xml") - try verifyAsset(root: tempDir.url, path: "/img/image.png", body: "png", type: "image/png") - try verifyAsset(root: tempDir.url, path: "/img/image.gif", body: "gif", type: "image/gif") + try verifyAsset(root: tempFolderURL, path: "/images/image.jpg", body: "jpg", type: "image/jpeg") + try verifyAsset(root: tempFolderURL, path: "/images/logo.svg", body: "svg", type: "image/svg+xml") + try verifyAsset(root: tempFolderURL, path: "/img/image.png", body: "png", type: "image/png") + try verifyAsset(root: tempFolderURL, path: "/img/image.gif", body: "gif", type: "image/gif") // default image type - try verifyAsset(root: tempDir.url, path: "/img/image.jpg", body: "jpg", type: "image/jpeg") - try verifyAsset(root: tempDir.url, path: "/videos/video.mov", body: "mov", type: "video/quicktime") - try verifyAsset(root: tempDir.url, path: "/videos/video.avi", body: "avi", type: "video/x-msvideo") - try verifyAsset(root: tempDir.url, path: "/downloads/project.zip", body: "zip", type: "application/zip") + try verifyAsset(root: tempFolderURL, path: "/img/image.jpg", body: "jpg", type: "image/jpeg") + try verifyAsset(root: tempFolderURL, path: "/videos/video.mov", body: "mov", type: "video/quicktime") + try verifyAsset(root: tempFolderURL, path: "/videos/video.avi", body: "avi", type: "video/x-msvideo") + try verifyAsset(root: tempFolderURL, path: "/downloads/project.zip", body: "zip", type: "application/zip") } func testFileHandlerAssetsMissing() throws { - let tempDir = try TempFolder(content: []) - try tempDir.write(to: URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString))) + let tempFolderURL = try createTempFolder(content: []) let request = makeRequestHead(path: "/css/b00011100.css") - let factory = FileRequestHandler(rootURL: tempDir.url, fileIO: fileIO) + let factory = FileRequestHandler(rootURL: tempFolderURL, fileIO: fileIO) let response = try responseWithPipeline(request: request, handler: factory) XCTAssertEqual(response.requestError?.status, .notFound) } func testFileHandlerWithRange() throws { - let tempDir = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ Folder(name: "videos", content: [ TextFile(name: "video.mov", utf8Content: "Hello!"), ]) ]) - try tempDir.write(to: URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString))) let request = makeRequestHead(path: "/videos/video.mov", headers: [("Range", "bytes=0-1")]) - let factory = FileRequestHandler(rootURL: tempDir.url, fileIO: fileIO) + let factory = FileRequestHandler(rootURL: tempFolderURL, fileIO: fileIO) let response = try responseWithPipeline(request: request, handler: factory) XCTAssertEqual(response.body, "He") @@ -118,15 +116,14 @@ class FileRequestHandlerTests: XCTestCase { } func testFileInUpperDirectory() throws { - let tempDir = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ Folder(name: "videos", content: [ TextFile(name: "video.mov", utf8Content: "Hello!"), ]) ]) - try tempDir.write(to: URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString))) let request = makeRequestHead(path: "/videos/../video.mov", headers: [("Range", "bytes=0-1")]) - let factory = FileRequestHandler(rootURL: tempDir.url, fileIO: fileIO) + let factory = FileRequestHandler(rootURL: tempFolderURL, fileIO: fileIO) let response = try responseWithPipeline(request: request, handler: factory) XCTAssertNil(response.body, "He") @@ -134,15 +131,14 @@ class FileRequestHandlerTests: XCTestCase { } func testMalformedPath() throws { - let tempDir = try TempFolder(content: [ + let tempFolderURL = try createTempFolder(content: [ Folder(name: "videos", content: [ TextFile(name: "video.mov", utf8Content: "Hello!"), ]) ]) - try tempDir.write(to: URL(fileURLWithPath: NSTemporaryDirectory().appending(UUID().uuidString))) let request = makeRequestHead(path: "/videos/. ? ? ? ./video.mov", headers: [("Range", "bytes=0-1")]) - let factory = FileRequestHandler(rootURL: tempDir.url, fileIO: fileIO) + let factory = FileRequestHandler(rootURL: tempFolderURL, fileIO: fileIO) let response = try responseWithPipeline(request: request, handler: factory) XCTAssertNil(response.body, "He") diff --git a/Tests/SwiftDocCUtilitiesTests/SemanticAnalyzerTests.swift b/Tests/SwiftDocCUtilitiesTests/SemanticAnalyzerTests.swift index 10d48f98c3..59af3ff9e7 100644 --- a/Tests/SwiftDocCUtilitiesTests/SemanticAnalyzerTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/SemanticAnalyzerTests.swift @@ -12,14 +12,9 @@ import XCTest import Markdown @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities class SemanticAnalyzerTests: XCTestCase { - func createTemporaryDirectory() throws -> URL { - let url = Foundation.URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString) - try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil) - return url - } - let bundleFolderHierarchy = Folder(name: "SemanticAnalyzerTests.docc", content: [ Folder(name: "Symbols", content: []), Folder(name: "Resources", content: [ diff --git a/Tests/SwiftDocCUtilitiesTests/ShadowFileManagerTemporaryDirectory.swift b/Tests/SwiftDocCUtilitiesTests/ShadowFileManagerTemporaryDirectory.swift new file mode 100644 index 0000000000..c7602c156f --- /dev/null +++ b/Tests/SwiftDocCUtilitiesTests/ShadowFileManagerTemporaryDirectory.swift @@ -0,0 +1,23 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation +import XCTest + +// This file exists to shadow `FileManager.temporaryDirectory` in unit tests to warn about potentially referencing a shared location if multiple checkouts run tests at the same time in Swift CI. + +extension FileManager { + + @available(*, deprecated, message: "Use `createTemporaryDirectory` instead in unit tests to avoid referencing a shared location in Swift CI.") + var temporaryDirectory: URL { + XCTFail("Use `createTemporaryDirectory` instead in unit tests to avoid referencing a shared location in Swift CI.") + return URL(fileURLWithPath: Foundation.NSTemporaryDirectory()) + } +} diff --git a/Tests/SwiftDocCUtilitiesTests/StaticHostableTransformerTests.swift b/Tests/SwiftDocCUtilitiesTests/StaticHostableTransformerTests.swift index 6038bbd349..b31a7e8bf6 100644 --- a/Tests/SwiftDocCUtilitiesTests/StaticHostableTransformerTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/StaticHostableTransformerTests.swift @@ -12,6 +12,7 @@ import XCTest import Foundation @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities class StaticHostableTransformerTests: StaticHostingBaseTests { @@ -20,14 +21,11 @@ class StaticHostableTransformerTests: StaticHostingBaseTests { // Convert a test bundle as input for the StaticHostableTransformer let bundleURL = Bundle.module.url(forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let fileManager = FileManager.default - try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - defer { try? fileManager.removeItem(at: targetURL) } - - let templateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let templateURL = try createTemporaryDirectory().appendingPathComponent("template") try Folder.emptyHTMLTemplateDirectory.write(to: templateURL) defer { try? fileManager.removeItem(at: templateURL) } @@ -41,17 +39,16 @@ class StaticHostableTransformerTests: StaticHostingBaseTests { targetDirectory: targetBundleURL, htmlTemplateDirectory: templateURL, emitDigest: false, - currentPlatforms: nil + currentPlatforms: nil, + temporaryDirectory: createTemporaryDirectory() ) _ = try action.perform(logHandle: .standardOutput) - let outputURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - defer { try? fileManager.removeItem(at: outputURL) } + let outputURL = try createTemporaryDirectory().appendingPathComponent("output") - let testTemplateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let testTemplateURL = try createTemporaryDirectory().appendingPathComponent("testTemplate") try Folder.testHTMLTemplateDirectory.write(to: testTemplateURL) - defer { try? fileManager.removeItem(at: testTemplateURL) } let basePath = "test/folder" let indexHTML = Folder.testHTMLTemplate(basePath: basePath) @@ -103,10 +100,8 @@ class StaticHostableTransformerTests: StaticHostingBaseTests { /// Creates a DocC archive and then archive then executes and TransformForStaticHostingAction on it to produce static content which is then validated. func testStaticHostableTransformerBasePaths() throws { - - let testTemplateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let testTemplateURL = try createTemporaryDirectory().appendingPathComponent("testTemplate") try Folder.testHTMLTemplateDirectory.write(to: testTemplateURL) - defer { try? FileManager.default.removeItem(at: testTemplateURL) } let basePaths = ["test": "test", "/test": "test", @@ -126,27 +121,16 @@ class StaticHostableTransformerTests: StaticHostingBaseTests { XCTAssertEqual(indexHTML, testIndexHTML, "Template HTML not transformed as expected") } } - - func testStaticHostableTransformerIndexHTMLOutput() throws { - // Convert a test bundle as input for the StaticHostableTransformer let bundleURL = Bundle.module.url(forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - - let fileManager = FileManager.default - try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - - defer { try? fileManager.removeItem(at: targetURL) } - - let templateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() + let templateURL = try createTemporaryDirectory().appendingPathComponent("template") try Folder.emptyHTMLTemplateDirectory.write(to: templateURL) - defer { try? fileManager.removeItem(at: templateURL) } let targetBundleURL = targetURL.appendingPathComponent("Result.doccarchive") - defer { try? fileManager.removeItem(at: targetBundleURL) } var action = try ConvertAction( documentationBundleURL: bundleURL, @@ -155,7 +139,8 @@ class StaticHostableTransformerTests: StaticHostingBaseTests { targetDirectory: targetBundleURL, htmlTemplateDirectory: templateURL, emitDigest: false, - currentPlatforms: nil + currentPlatforms: nil, + temporaryDirectory: createTemporaryDirectory() ) _ = try action.perform(logHandle: .standardOutput) @@ -163,9 +148,8 @@ class StaticHostableTransformerTests: StaticHostingBaseTests { let dataURL = targetBundleURL.appendingPathComponent(NodeURLGenerator.Path.dataFolderName) let dataProvider = try LocalFileSystemDataProvider(rootURL: dataURL) - let testTemplateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let testTemplateURL = try createTemporaryDirectory().appendingPathComponent("testTemplate") try Folder.testHTMLTemplateDirectory.write(to: testTemplateURL) - defer { try? fileManager.removeItem(at: testTemplateURL) } let basePaths = ["test": "test", "/test": "test", @@ -176,11 +160,9 @@ class StaticHostableTransformerTests: StaticHostingBaseTests { "test/test/": "test/test", "/test/test/": "test/test"] + let fileManager = FileManager.default for (basePath, testValue) in basePaths { - - let outputURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - defer { try? fileManager.removeItem(at: outputURL) } - + let outputURL = try createTemporaryDirectory().appendingPathComponent("output") let indexHTMLData = try StaticHostableTransformer.transformHTMLTemplate(htmlTemplate: testTemplateURL, hostingBasePath: basePath) let transformer = StaticHostableTransformer(dataProvider: dataProvider, fileManager: fileManager, outputURL: outputURL, indexHTMLData: indexHTMLData) diff --git a/Tests/SwiftDocCUtilitiesTests/TempFolderTests.swift b/Tests/SwiftDocCUtilitiesTests/TempFolderTests.swift deleted file mode 100644 index a80e5cddca..0000000000 --- a/Tests/SwiftDocCUtilitiesTests/TempFolderTests.swift +++ /dev/null @@ -1,46 +0,0 @@ -/* - This source file is part of the Swift.org open source project - - Copyright (c) 2021 Apple Inc. and the Swift project authors - Licensed under Apache License v2.0 with Runtime Library Exception - - See https://swift.org/LICENSE.txt for license information - See https://swift.org/CONTRIBUTORS.txt for Swift project authors -*/ - -import Foundation -import XCTest -@testable import SwiftDocC - -class TempFolderTests: XCTestCase { - func testCreatesAndDeletesTempFolder() throws { - var tempFolder: TempFolder? = try TempFolder(content: [ - TextFile(name: "index.html", utf8Content: "index"), - ]) - - // Below is safe to unwrap tempFolder because the initializer does not return an optional. - - // Check the folder is created and the file inside exists. - XCTAssertTrue(FileManager.default.directoryExists(atPath: tempFolder!.url.path)) - XCTAssertTrue(FileManager.default.fileExists(atPath: tempFolder!.url.appendingPathComponent("index.html").path)) - - let rootTempFolderPath = NSTemporaryDirectory() - - // Check the temp folder is inside the system temporary folder. - XCTAssertTrue(tempFolder!.url.path.contains(rootTempFolderPath)) - - let tempFolderURL = tempFolder!.url - - tempFolder = nil - - // Check the temp folder and contents are deleted immediately. - XCTAssertFalse(FileManager.default.fileExists(atPath: tempFolderURL.path)) - } - - func testCreatesRandomPaths() throws { - let tempFolder1 = try TempFolder(content: []) - let tempFolder2 = try TempFolder(content: []) - - XCTAssertNotEqual(tempFolder1.url, tempFolder2.url) - } -} diff --git a/Tests/SwiftDocCUtilitiesTests/TransformForStaticHostingActionTests.swift b/Tests/SwiftDocCUtilitiesTests/TransformForStaticHostingActionTests.swift index 6409388bfb..7d5ca49f71 100644 --- a/Tests/SwiftDocCUtilitiesTests/TransformForStaticHostingActionTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/TransformForStaticHostingActionTests.swift @@ -12,6 +12,7 @@ import XCTest import Foundation @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities class TransformForStaticHostingActionTests: StaticHostingBaseTests { @@ -20,19 +21,12 @@ class TransformForStaticHostingActionTests: StaticHostingBaseTests { // Convert a test bundle as input for the TransformForStaticHostingAction let bundleURL = Bundle.module.url(forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - - let fileManager = FileManager.default - try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) - - defer { try? fileManager.removeItem(at: targetURL) } + let targetURL = try createTemporaryDirectory() - let templateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let templateURL = try createTemporaryDirectory().appendingPathComponent("template") try Folder.emptyHTMLTemplateDirectory.write(to: templateURL) - defer { try? fileManager.removeItem(at: templateURL) } let targetBundleURL = targetURL.appendingPathComponent("Result.doccarchive") - defer { try? fileManager.removeItem(at: targetBundleURL) } var action = try ConvertAction( documentationBundleURL: bundleURL, @@ -41,28 +35,27 @@ class TransformForStaticHostingActionTests: StaticHostingBaseTests { targetDirectory: targetBundleURL, htmlTemplateDirectory: templateURL, emitDigest: false, - currentPlatforms: nil + currentPlatforms: nil, + temporaryDirectory: try createTemporaryDirectory() ) _ = try action.perform(logHandle: .standardOutput) - let outputURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) - defer { try? fileManager.removeItem(at: outputURL) } + let outputURL = try createTemporaryDirectory()//.appendingPathComponent("output") let basePath = "test/folder" - let testTemplateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let testTemplateURL = try createTemporaryDirectory().appendingPathComponent("testTemplate") let templateFolder = Folder.testHTMLTemplateDirectory try templateFolder.write(to: testTemplateURL) let indexHTML = Folder.testHTMLTemplate(basePath: basePath) - defer { try? fileManager.removeItem(at: testTemplateURL) } - var transformAction = try TransformForStaticHostingAction(documentationBundleURL: targetBundleURL, outputURL: outputURL, hostingBasePath: basePath, htmlTemplateDirectory: testTemplateURL) _ = try transformAction.perform(logHandle: .standardOutput) + let fileManager = FileManager.default var isDirectory: ObjCBool = false // Test an output folder exists @@ -109,15 +102,14 @@ class TransformForStaticHostingActionTests: StaticHostingBaseTests { // Convert a test bundle as input for the TransformForStaticHostingAction let bundleURL = Bundle.module.url(forResource: "TestBundle", withExtension: "docc", subdirectory: "Test Bundles")! - let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let targetURL = try createTemporaryDirectory() let fileManager = FileManager.default try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil) defer { try? fileManager.removeItem(at: targetURL) } - let templateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let templateURL = try createTemporaryDirectory().appendingPathComponent("template") try Folder.emptyHTMLTemplateDirectory.write(to: templateURL) - defer { try? fileManager.removeItem(at: templateURL) } let targetBundleURL = targetURL.appendingPathComponent("Result.doccarchive") @@ -128,21 +120,20 @@ class TransformForStaticHostingActionTests: StaticHostingBaseTests { targetDirectory: targetBundleURL, htmlTemplateDirectory: templateURL, emitDigest: false, - currentPlatforms: nil + currentPlatforms: nil, + temporaryDirectory: try createTemporaryDirectory() ) _ = try action.perform(logHandle: .standardOutput) let basePath = "test/folder" - let testTemplateURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) + let testTemplateURL = try createTemporaryDirectory().appendingPathComponent("testTemplate") let templateFolder = Folder.testHTMLTemplateDirectory try templateFolder.write(to: testTemplateURL) let indexHTML = Folder.testHTMLTemplate(basePath: basePath) var expectedContent = try fileManager.contentsOfDirectory(atPath: targetBundleURL.path) - - defer { try? fileManager.removeItem(at: testTemplateURL) } var transformAction = try TransformForStaticHostingAction(documentationBundleURL: targetBundleURL, outputURL: nil, hostingBasePath: basePath, htmlTemplateDirectory: testTemplateURL) diff --git a/Tests/SwiftDocCUtilitiesTests/Utility/FileTests.swift b/Tests/SwiftDocCUtilitiesTests/Utility/FileTests.swift index 96336e15d3..e1286a33fc 100644 --- a/Tests/SwiftDocCUtilitiesTests/Utility/FileTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/Utility/FileTests.swift @@ -11,6 +11,7 @@ import XCTest @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities class FileTests: XCTestCase { func testAbsoluteURL() { diff --git a/Tests/SwiftDocCUtilitiesTests/Utility/TestFileSystem.swift b/Tests/SwiftDocCUtilitiesTests/Utility/TestFileSystem.swift index fcc7138b8d..dc79be4c8c 100644 --- a/Tests/SwiftDocCUtilitiesTests/Utility/TestFileSystem.swift +++ b/Tests/SwiftDocCUtilitiesTests/Utility/TestFileSystem.swift @@ -12,6 +12,7 @@ import Foundation import XCTest @testable import SwiftDocCUtilities @testable import SwiftDocC +import SwiftDocCTestUtilities /// A Data provider and file manager that accepts pre-built documentation bundles with files on the local filesystem. /// @@ -70,7 +71,6 @@ class TestFileSystem: FileManagerProtocol, DocumentationWorkspaceDataProvider { // Default system paths files["/"] = Self.folderFixtureData - files[NSTemporaryDirectory()] = Self.folderFixtureData // Import given folders try updateDocumentationBundles(withFolders: folders) diff --git a/Tests/SwiftDocCUtilitiesTests/Utility/TestFileSystemTests.swift b/Tests/SwiftDocCUtilitiesTests/Utility/TestFileSystemTests.swift index 469751f652..ae041e2c61 100644 --- a/Tests/SwiftDocCUtilitiesTests/Utility/TestFileSystemTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/Utility/TestFileSystemTests.swift @@ -11,6 +11,7 @@ import XCTest @testable import SwiftDocC @testable import SwiftDocCUtilities +import SwiftDocCTestUtilities class TestFileSystemTests: XCTestCase { @@ -21,8 +22,7 @@ class TestFileSystemTests: XCTestCase { XCTAssertTrue(try fs.bundles().isEmpty) var isDirectory = ObjCBool(false) XCTAssertTrue(fs.fileExists(atPath: "/", isDirectory: &isDirectory)) - XCTAssertTrue(isDirectory.boolValue) - XCTAssertTrue(fs.fileExists(atPath: NSTemporaryDirectory(), isDirectory: &isDirectory)) + XCTAssertEqual(fs.files.keys.sorted(), ["/"], "The root (/) should be the only existing path.") XCTAssertTrue(isDirectory.boolValue) XCTAssertFalse(fs.disableWriting) } @@ -36,7 +36,6 @@ class TestFileSystemTests: XCTestCase { let folder2 = Folder(name: "additional", content: []) let fs = try TestFileSystem(folders: [folder1, folder2]) - try fs.removeItem(at: URL(string: NSTemporaryDirectory())!) // Verify correct folders & files var isDirectory = ObjCBool(false) @@ -68,9 +67,6 @@ class TestFileSystemTests: XCTestCase { ]) let fs = try TestFileSystem(folders: [folder]) - - // Remove temp folder since the path is random on macOS and we can't do efficient comparisson of the dump - try fs.removeItem(at: URL(string: NSTemporaryDirectory())!) XCTAssertEqual(fs.dump(), """ / @@ -214,7 +210,6 @@ class TestFileSystemTests: XCTestCase { func testCreateDeeplyNestedDirectory() throws { let fs = try TestFileSystem(folders: []) - try fs.removeItem(at: URL(string: NSTemporaryDirectory())!) // Test if creates deeply nested directory structure try fs.createDirectory(at: URL(string: "/one/two/three/four/five/six")!, withIntermediateDirectories: true)