Skip to content

Commit 1003707

Browse files
authored
Merge branch 'main' into droid
2 parents 82e3221 + 664d24f commit 1003707

File tree

7 files changed

+182
-0
lines changed

7 files changed

+182
-0
lines changed

.github/workflows/pull_request.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ jobs:
2121
windows_swift_versions: '["nightly-main", "nightly-6.2"]'
2222
enable_macos_checks: true
2323
macos_exclude_xcode_versions: '[{"xcode_version": "16.2"}, {"xcode_version": "16.3"}, {"xcode_version": "16.4"}]'
24+
enable_ios_checks: true
25+
ios_host_exclude_xcode_versions: '[{"xcode_version": "16.2"}, {"xcode_version": "16.3"}, {"xcode_version": "16.4"}]'
2426
enable_wasm_sdk_build: true
27+
enable_android_sdk_build: true
2528
soundness:
2629
name: Soundness
2730
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main

Package.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,17 @@ let package = Package(
105105
)
106106
)
107107

108+
#if DEBUG
109+
// Build _TestingInterop for debugging/testing purposes only. It is
110+
// important that clients do not link to this product/target.
111+
result += [
112+
.library(
113+
name: "_TestingInterop_DO_NOT_USE",
114+
targets: ["_TestingInterop_DO_NOT_USE"]
115+
)
116+
]
117+
#endif
118+
108119
return result
109120
}(),
110121

@@ -209,6 +220,16 @@ let package = Package(
209220
cxxSettings: .packageSettings,
210221
swiftSettings: .packageSettings + .enableLibraryEvolution()
211222
),
223+
.target(
224+
// Build _TestingInterop for debugging/testing purposes only. It is
225+
// important that clients do not link to this product/target.
226+
name: "_TestingInterop_DO_NOT_USE",
227+
dependencies: ["_TestingInternals",],
228+
path: "Sources/_TestingInterop",
229+
exclude: ["CMakeLists.txt"],
230+
cxxSettings: .packageSettings,
231+
swiftSettings: .packageSettings
232+
),
212233

213234
// Cross-import overlays (not supported by Swift Package Manager)
214235
.target(

Sources/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ endif()
104104
include(AvailabilityDefinitions)
105105
include(CompilerSettings)
106106
add_subdirectory(_TestDiscovery)
107+
add_subdirectory(_TestingInterop)
107108
add_subdirectory(_TestingInternals)
108109
add_subdirectory(Overlays)
109110
add_subdirectory(Testing)

Sources/Testing/Attachments/Attachment.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ public struct AnyAttachable: AttachableWrapper, Sendable, Copyable {
193193

194194
// MARK: - Describing an attachment
195195

196+
@_preInverseGenerics
196197
extension Attachment: CustomStringConvertible where AttachableValue: ~Copyable {
197198
/// @Metadata {
198199
/// @Available(Swift, introduced: 6.2)

Sources/Testing/ExitTests/ExitTest.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ extension ExitTest {
392392
///
393393
/// - Warning: This function is used to implement the
394394
/// `#expect(processExitsWith:)` macro. Do not use it directly.
395+
@_disfavoredOverload
395396
@safe public static func __store<T>(
396397
_ id: (UInt64, UInt64, UInt64, UInt64),
397398
_ body: T,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# This source file is part of the Swift.org open source project
2+
#
3+
# Copyright (c) 2025 Apple Inc. and the Swift project authors
4+
# Licensed under Apache License v2.0 with Runtime Library Exception
5+
#
6+
# See http://swift.org/LICENSE.txt for license information
7+
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
8+
9+
add_library(_TestingInterop
10+
FallbackEventHandler.swift)
11+
12+
target_link_libraries(_TestingInterop PRIVATE
13+
_TestingInternals)
14+
if(NOT BUILD_SHARED_LIBS)
15+
# When building a static library, tell clients to autolink the internal
16+
# libraries.
17+
target_compile_options(_TestingInterop PRIVATE
18+
"SHELL:-Xfrontend -public-autolink-library -Xfrontend _TestingInternals")
19+
endif()
20+
target_compile_options(_TestingInterop PRIVATE
21+
-enable-library-evolution
22+
-emit-module-interface -emit-module-interface-path $<TARGET_PROPERTY:_TestingInterop,Swift_MODULE_DIRECTORY>/_TestingInterop.swiftinterface)
23+
24+
_swift_testing_install_target(_TestingInterop)
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//
2+
// This source file is part of the Swift.org open source project
3+
//
4+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
5+
// Licensed under Apache License v2.0 with Runtime Library Exception
6+
//
7+
// See https://swift.org/LICENSE.txt for license information
8+
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
//
10+
11+
#if !SWT_NO_INTEROP
12+
#if SWT_TARGET_OS_APPLE && !SWT_NO_OS_UNFAIR_LOCK && !hasFeature(Embedded)
13+
private import _TestingInternals
14+
#else
15+
private import Synchronization
16+
#endif
17+
18+
#if SWT_TARGET_OS_APPLE && !SWT_NO_OS_UNFAIR_LOCK && !hasFeature(Embedded)
19+
/// The installed event handler.
20+
private nonisolated(unsafe) let _fallbackEventHandler = {
21+
let result = ManagedBuffer<FallbackEventHandler?, os_unfair_lock>.create(
22+
minimumCapacity: 1,
23+
makingHeaderWith: { _ in nil }
24+
)
25+
result.withUnsafeMutablePointerToHeader { $0.initialize(to: nil) }
26+
return result
27+
}()
28+
#else
29+
/// `Atomic`-compatible storage for ``FallbackEventHandler``.
30+
private final class _FallbackEventHandlerStorage: Sendable, RawRepresentable {
31+
let rawValue: FallbackEventHandler
32+
33+
init(rawValue: FallbackEventHandler) {
34+
self.rawValue = rawValue
35+
}
36+
}
37+
38+
/// The installed event handler.
39+
private let _fallbackEventHandler = Atomic<Unmanaged<_FallbackEventHandlerStorage>?>(nil)
40+
#endif
41+
42+
/// A type describing a fallback event handler that testing API can invoke as an
43+
/// alternate method of reporting test events to the current test runner.
44+
///
45+
/// For example, an `XCTAssert` failure in the body of a Swift Testing test
46+
/// cannot record issues directly with the Swift Testing runner. Instead, the
47+
/// framework packages the assertion failure as a JSON `Event` and invokes this
48+
/// handler to report the failure.
49+
///
50+
/// - Parameters:
51+
/// - recordJSONSchemaVersionNumber: The JSON schema version used to encode
52+
/// the event record.
53+
/// - recordJSONBaseAddress: A pointer to the first byte of the encoded event.
54+
/// - recordJSONByteCount: The size of the encoded event in bytes.
55+
/// - reserved: Reserved for future use.
56+
@usableFromInline
57+
package typealias FallbackEventHandler = @Sendable @convention(c) (
58+
_ recordJSONSchemaVersionNumber: UnsafePointer<CChar>,
59+
_ recordJSONBaseAddress: UnsafeRawPointer,
60+
_ recordJSONByteCount: Int,
61+
_ reserved: UnsafeRawPointer?
62+
) -> Void
63+
64+
/// Get the current fallback event handler.
65+
///
66+
/// - Returns: The currently-set handler function, if any.
67+
@_cdecl("_swift_testing_getFallbackEventHandler")
68+
@usableFromInline
69+
package func _swift_testing_getFallbackEventHandler() -> FallbackEventHandler? {
70+
#if SWT_TARGET_OS_APPLE && !SWT_NO_OS_UNFAIR_LOCK && !hasFeature(Embedded)
71+
return _fallbackEventHandler.withUnsafeMutablePointers { fallbackEventHandler, lock in
72+
os_unfair_lock_lock(lock)
73+
defer {
74+
os_unfair_lock_unlock(lock)
75+
}
76+
return fallbackEventHandler.pointee
77+
}
78+
#else
79+
// If we had a setter, this load would present a race condition because
80+
// another thread could store a new value in between the load and the call to
81+
// `takeUnretainedValue()`, resulting in a use-after-free on this thread. We
82+
// would need a full lock in order to avoid that problem. However, because we
83+
// instead have a one-time installation function, we can be sure that the
84+
// loaded value (if non-nil) will never be replaced with another value.
85+
return _fallbackEventHandler.load(ordering: .sequentiallyConsistent).map { fallbackEventHandler in
86+
fallbackEventHandler.takeUnretainedValue().rawValue
87+
}
88+
#endif
89+
}
90+
91+
/// Set the current fallback event handler if one has not already been set.
92+
///
93+
/// - Parameters:
94+
/// - handler: The handler function to set.
95+
///
96+
/// - Returns: Whether or not `handler` was installed.
97+
///
98+
/// The fallback event handler can only be installed once per process, typically
99+
/// by the first testing library to run. If this function has already been
100+
/// called and the handler set, it does not replace the previous handler.
101+
@_cdecl("_swift_testing_installFallbackEventHandler")
102+
@usableFromInline
103+
package func _swift_testing_installFallbackEventHandler(_ handler: FallbackEventHandler) -> CBool {
104+
var result = false
105+
106+
#if SWT_TARGET_OS_APPLE && !SWT_NO_OS_UNFAIR_LOCK && !hasFeature(Embedded)
107+
result = _fallbackEventHandler.withUnsafeMutablePointers { fallbackEventHandler, lock in
108+
os_unfair_lock_lock(lock)
109+
defer {
110+
os_unfair_lock_unlock(lock)
111+
}
112+
guard fallbackEventHandler.pointee == nil else {
113+
return false
114+
}
115+
fallbackEventHandler.pointee = handler
116+
return true
117+
}
118+
#else
119+
let handler = Unmanaged.passRetained(_FallbackEventHandlerStorage(rawValue: handler))
120+
defer {
121+
if !result {
122+
handler.release()
123+
}
124+
}
125+
126+
result = _fallbackEventHandler.compareExchange(expected: nil, desired: handler, ordering: .sequentiallyConsistent).exchanged
127+
#endif
128+
129+
return result
130+
}
131+
#endif

0 commit comments

Comments
 (0)