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
|
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2023–2025 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
//
@_spi(Experimental) @_spi(ForToolsIntegrationOnly) private import _TestDiscovery
private import _TestingInternals
extension Test {
/// A type that encapsulates test content records that produce instances of
/// ``Test``.
///
/// This type is necessary because such test content records produce an
/// indirect `async` accessor function rather than directly producing
/// instances of ``Test``, but functions are non-nominal types and cannot
/// directly conform to protocols.
fileprivate struct Generator: DiscoverableAsTestContent, RawRepresentable {
static var testContentKind: TestContentKind {
"test"
}
var rawValue: @Sendable () async -> Test
}
/// Store the test generator function into the given memory.
///
/// - Parameters:
/// - generator: The generator function to store.
/// - outValue: The uninitialized memory to store `generator` into.
/// - typeAddress: A pointer to the expected type of `generator` as passed
/// to the test content record calling this function.
///
/// - Returns: Whether or not `generator` was stored into `outValue`.
///
/// - Warning: This function is used to implement the `@Test` macro. Do not
/// use it directly.
#if compiler(>=6.2)
@safe
#endif
public static func __store(
_ generator: @escaping @Sendable () async -> Test,
into outValue: UnsafeMutableRawPointer,
asTypeAt typeAddress: UnsafeRawPointer
) -> CBool {
#if !hasFeature(Embedded)
guard typeAddress.load(as: Any.Type.self) == Generator.self else {
return false
}
#endif
outValue.initializeMemory(as: Generator.self, to: .init(rawValue: generator))
return true
}
/// All available ``Test`` instances in the process, according to the runtime.
///
/// The order of values in this sequence is unspecified.
static var all: some Sequence<Self> {
get async {
// The result is a set rather than an array to deduplicate tests that were
// generated multiple times (e.g. from multiple discovery modes or from
// defective test records.)
var result = Set<Self>()
// Figure out which discovery mechanism to use. By default, we'll use both
// the legacy and new mechanisms, but we can set an environment variable
// to explicitly select one or the other. When we remove legacy support,
// we can also remove this enumeration and environment variable check.
#if !SWT_NO_LEGACY_TEST_DISCOVERY
let (useNewMode, useLegacyMode) = switch Environment.flag(named: "SWT_USE_LEGACY_TEST_DISCOVERY") {
case .none:
(true, true)
case .some(true):
(false, true)
case .some(false):
(true, false)
}
#else
let useNewMode = true
#endif
// Walk all test content and gather generator functions, then call them in
// a task group and collate their results.
if useNewMode {
let generators = Generator.allTestContentRecords().lazy.compactMap { $0.load() }
await withTaskGroup { taskGroup in
for generator in generators {
taskGroup.addTask { await generator.rawValue() }
}
result = await taskGroup.reduce(into: result) { $0.insert($1) }
}
}
#if !SWT_NO_LEGACY_TEST_DISCOVERY
// Perform legacy test discovery if needed.
if useLegacyMode && result.isEmpty {
let generators = Generator.allTypeMetadataBasedTestContentRecords().lazy.compactMap { $0.load() }
await withTaskGroup { taskGroup in
for generator in generators {
taskGroup.addTask { await generator.rawValue() }
}
result = await taskGroup.reduce(into: result) { $0.insert($1) }
}
}
#endif
return result
}
}
}
|