-
Notifications
You must be signed in to change notification settings - Fork 103
/
Copy pathABIv0.Record+Streaming.swift
154 lines (145 loc) · 5.91 KB
/
ABIv0.Record+Streaming.swift
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
//
// 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_FILE_IO || !SWT_NO_ABI_ENTRY_POINT)
extension ABIv0.Record {
/// Post-process encoded JSON and write it to a file.
///
/// - Parameters:
/// - json: The JSON to write.
/// - file: The file to write to.
///
/// - Throws: Whatever is thrown when writing to `file`.
private static func _asJSONLine(_ json: UnsafeRawBufferPointer, _ eventHandler: (_ recordJSON: UnsafeRawBufferPointer) throws -> Void) rethrows {
// We don't actually expect the JSON encoder to produce output containing
// newline characters, so in debug builds we'll log a diagnostic message.
if _slowPath(json.contains(where: \.isASCIINewline)) {
#if DEBUG
let message = Event.ConsoleOutputRecorder.warning(
"JSON encoder produced one or more newline characters while encoding an event to JSON. Please file a bug report at https://github.com/swiftlang/swift-testing/issues/new",
options: .for(.stderr)
)
#if SWT_TARGET_OS_APPLE
try? FileHandle.stderr.write(message)
#else
print(message)
#endif
#endif
// Remove the newline characters to conform to JSON lines specification.
var json = Array(json)
json.removeAll(where: \.isASCIINewline)
try json.withUnsafeBytes(eventHandler)
} else {
// No newlines found, no need to copy the buffer.
try eventHandler(json)
}
}
/// Create an event handler that encodes events as JSON and forwards them to
/// an ABI-friendly event handler.
///
/// - Parameters:
/// - encodeAsJSONLines: Whether or not to ensure JSON passed to
/// `eventHandler` is encoded as JSON Lines (i.e. that it does not contain
/// extra newlines.)
/// - eventHandler: The event handler to forward events to. See
/// ``ABIv0/EntryPoint-swift.typealias`` for more information.
///
/// - Returns: An event handler.
///
/// The resulting event handler outputs data as JSON. For each event handled
/// by the resulting event handler, a JSON object representing it and its
/// associated context is created and is passed to `eventHandler`.
///
/// Note that ``configurationForEntryPoint(from:)`` calls this function and
/// performs additional postprocessing before writing JSON data to ensure it
/// does not contain any newline characters.
static func eventHandler(
encodeAsJSONLines: Bool,
forwardingTo eventHandler: @escaping @Sendable (_ recordJSON: UnsafeRawBufferPointer) -> Void
) -> Event.Handler {
// Encode as JSON Lines if requested.
var eventHandlerCopy = eventHandler
if encodeAsJSONLines {
eventHandlerCopy = { @Sendable in _asJSONLine($0, eventHandler) }
}
let humanReadableOutputRecorder = Event.HumanReadableOutputRecorder()
return { [eventHandler = eventHandlerCopy] event, context in
if case .testDiscovered = event.kind, let test = context.test {
try? JSON.withEncoding(of: Self(encoding: test)) { testJSON in
eventHandler(testJSON)
}
} else {
let messages = humanReadableOutputRecorder.record(event, in: context, verbosity: 0)
if let eventRecord = Self(encoding: event, in: context, messages: messages) {
try? JSON.withEncoding(of: eventRecord, eventHandler)
}
}
}
}
}
#if !SWT_NO_SNAPSHOT_TYPES
// MARK: - Experimental event streaming
/// A type containing an event snapshot and snapshots of the contents of an
/// event context suitable for streaming over JSON.
///
/// This type is not part of the public interface of the testing library.
/// External adopters are not necessarily written in Swift and are expected to
/// decode the JSON produced for this type in implementation-specific ways.
///
/// - Warning: This type supports early Xcode 16 betas and will be removed in a
/// future update.
struct EventAndContextSnapshot {
/// A snapshot of the event.
var event: Event.Snapshot
/// A snapshot of the event context.
var eventContext: Event.Context.Snapshot
}
extension EventAndContextSnapshot: Codable {}
/// Create an event handler that encodes events as JSON and forwards them to an
/// ABI-friendly event handler.
///
/// - Parameters:
/// - eventHandler: The event handler to forward events to. See
/// ``ABIv0/EntryPoint-swift.typealias`` for more information.
///
/// - Returns: An event handler.
///
/// The resulting event handler outputs data as JSON. For each event handled by
/// the resulting event handler, a JSON object representing it and its
/// associated context is created and is passed to `eventHandler`.
///
/// Note that ``configurationForEntryPoint(from:)`` calls this function and
/// performs additional postprocessing before writing JSON data to ensure it
/// does not contain any newline characters.
///
/// - Warning: This function supports early Xcode 16 betas and will be removed
/// in a future update.
func eventHandlerForStreamingEventSnapshots(
to eventHandler: @escaping @Sendable (_ eventAndContextJSON: UnsafeRawBufferPointer) -> Void
) -> Event.Handler {
return { event, context in
if case .testDiscovered = event.kind {
// Discard events of this kind rather than forwarding them to avoid a
// crash in Xcode 16 Beta 1 (which does not expect any events to occur
// before .runStarted.)
return
}
let snapshot = EventAndContextSnapshot(
event: Event.Snapshot(snapshotting: event),
eventContext: Event.Context.Snapshot(snapshotting: context)
)
try? JSON.withEncoding(of: snapshot) { eventAndContextJSON in
eventAndContextJSON.withUnsafeBytes { eventAndContextJSON in
eventHandler(eventAndContextJSON)
}
}
}
}
#endif
#endif