1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
import Foundation
import XCTest
@testable import WIT
@testable import WITExtractor
struct TestSupport {
struct Configuration: Codable {
let hostSwiftExecutablePath: URL
let hostSdkRootPath: String?
var digesterPath: URL {
hostSwiftExecutablePath.deletingLastPathComponent().appendingPathComponent("swift-api-digester")
}
var hostSwiftFrontendPath: URL {
hostSwiftExecutablePath.deletingLastPathComponent().appendingPathComponent("swift-frontend")
}
static let `default`: Configuration? = {
let decoder = JSONDecoder()
let defaultsPath = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent() // WITExtractorTests
.deletingLastPathComponent() // Tests
.appendingPathComponent("default.json")
guard let bytes = try? Data(contentsOf: defaultsPath) else { return nil }
return try? decoder.decode(Configuration.self, from: bytes)
}()
}
struct Error: Swift.Error, CustomStringConvertible {
let description: String
init(description: String) {
self.description = description
}
init(errno: Int32) {
self.init(description: String(cString: strerror(errno)))
}
}
static func withTemporaryDirectory<Result>(
_ body: (String) throws -> Result
) throws -> Result {
let tempdir = URL(fileURLWithPath: NSTemporaryDirectory())
let templatePath = tempdir.appendingPathComponent("WasmKit.XXXXXX")
var template = [UInt8](templatePath.path.utf8).map({ Int8($0) }) + [Int8(0)]
#if os(Windows)
if _mktemp_s(&template, template.count) != 0 {
throw Error(errno: errno)
}
if _mkdir(template) != 0 {
throw Error(errno: errno)
}
#else
if mkdtemp(&template) == nil {
#if os(Android)
throw Error(errno: __errno().pointee)
#else
throw Error(errno: errno)
#endif
}
#endif
let path = String(cString: template)
defer { _ = try? FileManager.default.removeItem(atPath: path) }
return try body(path)
}
static func emitModule(
_ swiftSource: String,
moduleDir: URL,
moduleName: String,
config: Configuration
) throws {
#if os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
throw XCTSkip("WITExtractor does not support platforms where Foundation.Process is unavailable")
#else
let process = Process()
let stdinPipe = Pipe()
process.launchPath = config.hostSwiftFrontendPath.path
var arguments = [
"-parse-as-library", "-module-name", moduleName,
"-emit-module", "-", "-o", moduleDir.appendingPathComponent(moduleName + ".swiftmodule").path,
]
if let sdkRoot = config.hostSdkRootPath {
arguments.append(contentsOf: ["-sdk", sdkRoot])
}
process.arguments = arguments
process.standardInput = stdinPipe
try process.run()
try stdinPipe.fileHandleForWriting.write(contentsOf: Data(swiftSource.utf8))
try stdinPipe.fileHandleForWriting.close()
process.waitUntilExit()
guard process.terminationStatus == 0 else {
throw TestSupport.Error(
description: "Failed to execute \(([config.hostSwiftFrontendPath.path] + arguments).joined(separator: " "))"
)
}
#endif
}
static func assertTranslation(
_ swiftSource: String,
_ expectedWIT: String,
_ namespace: String = "swift",
_ packageName: String = "wasmkit",
_ moduleName: String = "test",
file: StaticString = #file,
line: UInt = #line
) throws {
#if os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
throw XCTSkip("WITExtractor does not support platforms where Foundation.Process is unavailable")
#else
guard let config = Configuration.default else {
throw XCTSkip("Please create 'Tests/default.json'")
}
var digesterArgs: [String] = []
if let sdkRoot = config.hostSdkRootPath {
digesterArgs.append(contentsOf: ["-sdk", sdkRoot])
}
let output = try withTemporaryDirectory { moduleDir in
try emitModule(
swiftSource,
moduleDir: URL(fileURLWithPath: moduleDir),
moduleName: moduleName,
config: config
)
digesterArgs.append(contentsOf: ["-I", moduleDir])
let extractor = WITExtractor(
namespace: namespace,
packageName: packageName,
digesterPath: config.digesterPath.path,
extraDigesterArguments: digesterArgs
)
return try extractor.runWithoutHeader(moduleName: moduleName).witContents
}
XCTAssertEqual(output, expectedWIT, file: file, line: line)
var lexer = Lexer(cursor: Lexer.Cursor(input: output))
XCTAssertNoThrow(try SourceFileSyntax.parse(lexer: &lexer, fileName: "test.wit"), "Extracted WIT file is invalid")
#endif
}
}
|