Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,20 @@ let package = Package(
exclude: ["CMakeLists.txt", "Testing.swiftcrossimport"],
cxxSettings: .packageSettings,
swiftSettings: .packageSettings + .enableLibraryEvolution(),
linkerSettings: [
.linkedLibrary("execinfo", .when(platforms: [.custom("freebsd"), .openbsd]))
]
linkerSettings: {
var result = [LinkerSetting]()
result += [
.linkedLibrary("execinfo", .when(platforms: [.custom("freebsd"), .openbsd]))
]
#if compiler(>=6.3)
result += [
.linkedFramework("_TestingInterop", .whenApple()),
.linkedLibrary("_TestingInterop", .whenApple(false)),
]
#endif

return result
}()
),
.testTarget(
name: "TestingTests",
Expand Down
1 change: 1 addition & 0 deletions Sources/Testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ add_library(Testing
Attachments/Attachment.swift
Events/Clock.swift
Events/Event.swift
Events/Event+FallbackHandler.swift
Events/Recorder/Event.AdvancedConsoleOutputRecorder.swift
Events/Recorder/Event.ConsoleOutputRecorder.swift
Events/Recorder/Event.HumanReadableOutputRecorder.swift
Expand Down
48 changes: 48 additions & 0 deletions Sources/Testing/Events/Event+FallbackHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 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
//

private import _TestingInternals

extension Event {
private static let _fallbackEventHandler: FallbackEventHandler? = {
_swift_testing_getFallbackEventHandler()
}()

/// Post this event to the currently-installed fallback event handler.
///
/// - Parameters:
/// - context: The context associated with this event.
///
/// - Returns: Whether or not the fallback event handler was invoked. If the
/// currently-installed handler belongs to the testing library, returns
/// `false`.
borrowing func postToFallbackHandler(in context: borrowing Context) -> Bool {
#if canImport(_TestingInterop)
guard let fallbackEventHandler = Self._fallbackEventHandler else {
return false
}

// Encode the event as JSON and pass it to the handler.
let encodeAndInvoke = ABI.CurrentVersion.eventHandler(encodeAsJSONLines: false) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to cache this event handler somewhere as there's a bit of runtime overhead to generating it. Remember the fallback event handler can't change after its initial assignment, and will be set by the time an event is generated, so we don't need to worry about it having changed on later calls (i.e. the closure we generate here can permanently capture it.)

recordJSON in
fallbackEventHandler(
String(describing: ABI.CurrentVersion.versionNumber),
recordJSON.baseAddress!,
recordJSON.count,
nil
)
}
encodeAndInvoke(self, context)
return true
#else
return false
#endif
}
}
2 changes: 2 additions & 0 deletions Sources/Testing/Events/Event.swift
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,8 @@ extension Event {
if configuration.eventHandlingOptions.shouldHandleEvent(self) {
configuration.handleEvent(self, in: context)
}
} else if postToFallbackHandler(in: context) {
// The fallback event handler handled this event.
} else {
// The current task does NOT have an associated configuration. This event
// will be lost! Post it to every registered event handler to avoid that.
Expand Down
26 changes: 26 additions & 0 deletions Sources/_TestingInternals/include/Stubs.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,32 @@ static int swt_setfdflags(int fd, int flags) {
}
#endif

// __SWIFT_COMPILER_VERSION is a packed value. The comparison below is >= 6.3
#if __SWIFT_COMPILER_VERSION >= 6003000000000 && !SWT_NO_INTEROP

/// A type describing a fallback event handler that testing API can invoke as an
/// alternate method of reporting test events to the current test runner.
/// Shadows the type with the same name in _TestingInterop.
///
/// - Parameters:
/// - recordJSONSchemaVersionNumber: The JSON schema version used to encode
/// the event record.
/// - recordJSONBaseAddress: A pointer to the first byte of the encoded event.
/// - recordJSONByteCount: The size of the encoded event in bytes.
/// - reserved: Reserved for future use.
typedef void (* FallbackEventHandler)(const char *recordJSONSchemaVersionNumber,
const void *recordJSONBaseAddress,
long recordJSONByteCount,
const void *_Nullable reserved);

/// Get the current fallback event handler.
/// Shadows the function with the same name in _TestingInterop.
///
/// - Returns: The currently-set handler function, if any.
SWT_EXTERN FallbackEventHandler _Nullable _swift_testing_getFallbackEventHandler(void);

#endif

SWT_ASSUME_NONNULL_END

#endif
2 changes: 1 addition & 1 deletion Sources/_TestingInterop/FallbackEventHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
//

#if !SWT_NO_INTEROP
#if compiler(>=6.3) && !SWT_NO_INTEROP
#if SWT_TARGET_OS_APPLE && !SWT_NO_OS_UNFAIR_LOCK && !hasFeature(Embedded)
private import _TestingInternals
#else
Expand Down
Loading