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 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 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
//
#if canImport(Foundation) && !SWT_NO_ABI_ENTRY_POINT
@testable @_spi(Experimental) @_spi(ForToolsIntegrationOnly) import Testing
#if canImport(Foundation)
private import Foundation
#endif
private import _TestingInternals
@Suite("ABI entry point tests")
struct ABIEntryPointTests {
#if !SWT_NO_SNAPSHOT_TYPES
@available(*, deprecated)
@Test func v0_experimental() async throws {
var arguments = __CommandLineArguments_v0()
arguments.filter = ["NonExistentTestThatMatchesNothingHopefully"]
arguments.eventStreamVersion = 0
arguments.verbosity = .min
let result = try await _invokeEntryPointV0Experimental(passing: arguments) { recordJSON in
let record = try! JSON.decode(ABIv0.Record.self, from: recordJSON)
_ = record.version
}
#expect(result == EXIT_SUCCESS)
}
@available(*, deprecated)
@Test("v0 experimental entry point with a large number of filter arguments")
func v0_experimental_manyFilters() async throws {
var arguments = __CommandLineArguments_v0()
arguments.filter = (1...100).map { "NonExistentTestThatMatchesNothingHopefully_\($0)" }
arguments.eventStreamVersion = 0
arguments.verbosity = .min
let result = try await _invokeEntryPointV0Experimental(passing: arguments)
#expect(result == EXIT_SUCCESS)
}
@available(*, deprecated)
private func _invokeEntryPointV0Experimental(
passing arguments: __CommandLineArguments_v0,
recordHandler: @escaping @Sendable (_ recordJSON: UnsafeRawBufferPointer) -> Void = { _ in }
) async throws -> CInt {
// Get the ABI entry point by dynamically looking it up at runtime.
let copyABIEntryPoint_v0 = try #require(
symbol(named: "swt_copyABIEntryPoint_v0").map {
unsafeBitCast($0, to: (@convention(c) () -> UnsafeMutableRawPointer).self)
}
)
let abiEntryPoint = copyABIEntryPoint_v0().assumingMemoryBound(to: ABIEntryPoint_v0.self)
defer {
abiEntryPoint.deinitialize(count: 1)
abiEntryPoint.deallocate()
}
let argumentsJSON = try JSON.withEncoding(of: arguments) { argumentsJSON in
let result = UnsafeMutableRawBufferPointer.allocate(byteCount: argumentsJSON.count, alignment: 1)
result.copyMemory(from: argumentsJSON)
return result
}
defer {
argumentsJSON.deallocate()
}
// Call the entry point function.
return try await abiEntryPoint.pointee(.init(argumentsJSON), recordHandler)
}
#endif
@Test func v0() async throws {
var arguments = __CommandLineArguments_v0()
arguments.filter = ["NonExistentTestThatMatchesNothingHopefully"]
arguments.eventStreamVersion = 0
arguments.verbosity = .min
let result = try await _invokeEntryPointV0(passing: arguments) { recordJSON in
let record = try! JSON.decode(ABIv0.Record.self, from: recordJSON)
_ = record.version
}
#expect(result)
}
@Test("v0 entry point with a large number of filter arguments")
func v0_manyFilters() async throws {
var arguments = __CommandLineArguments_v0()
arguments.filter = (1...100).map { "NonExistentTestThatMatchesNothingHopefully_\($0)" }
arguments.eventStreamVersion = 0
arguments.verbosity = .min
let result = try await _invokeEntryPointV0(passing: arguments)
#expect(result)
}
@Test("v0 entry point listing tests only")
func v0_listingTestsOnly() async throws {
var arguments = __CommandLineArguments_v0()
arguments.listTests = true
arguments.eventStreamVersion = 0
arguments.verbosity = .min
try await confirmation("Test matched", expectedCount: 1...) { testMatched in
_ = try await _invokeEntryPointV0(passing: arguments) { recordJSON in
let record = try! JSON.decode(ABIv0.Record.self, from: recordJSON)
if case .test = record.kind {
testMatched()
} else {
Issue.record("Unexpected record \(record)")
}
}
}
}
private func _invokeEntryPointV0(
passing arguments: __CommandLineArguments_v0,
recordHandler: @escaping @Sendable (_ recordJSON: UnsafeRawBufferPointer) -> Void = { _ in }
) async throws -> Bool {
#if !os(Linux) && !SWT_NO_DYNAMIC_LINKING
// Get the ABI entry point by dynamically looking it up at runtime.
//
// NOTE: The standard Linux linker does not allow exporting symbols from
// executables, so dlsym() does not let us find this function on that
// platform when built as an executable rather than a dynamic library.
let abiv0_getEntryPoint = try #require(
symbol(named: "swt_abiv0_getEntryPoint").map {
unsafeBitCast($0, to: (@convention(c) () -> UnsafeRawPointer).self)
}
)
#endif
let abiEntryPoint = unsafeBitCast(abiv0_getEntryPoint(), to: ABIv0.EntryPoint.self)
let argumentsJSON = try JSON.withEncoding(of: arguments) { argumentsJSON in
let result = UnsafeMutableRawBufferPointer.allocate(byteCount: argumentsJSON.count, alignment: 1)
result.copyMemory(from: argumentsJSON)
return result
}
defer {
argumentsJSON.deallocate()
}
// Call the entry point function.
return try await abiEntryPoint(.init(argumentsJSON), recordHandler)
}
#if canImport(Foundation)
@Test func decodeEmptyConfiguration() throws {
let emptyBuffer = UnsafeRawBufferPointer(start: nil, count: 0)
#expect(throws: DecodingError.self) {
_ = try JSON.decode(__CommandLineArguments_v0.self, from: emptyBuffer)
}
}
#endif
}
#endif
|