Skip to content

Commit 4be1dfe

Browse files
authored
Fix multiline comments not rendering correctly at CLI. (#850)
This PR fixes a bug where a multi-line comment or message written to `stderr` would only have its first line in grey and would not write atomically, resulting in odd/incorrect output. All messages generated by a test event are now written to `stderr` atomically. Resolves rdar://134519515. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 0098422 commit 4be1dfe

File tree

2 files changed

+30
-20
lines changed

2 files changed

+30
-20
lines changed

Sources/Testing/Events/Recorder/Event.ConsoleOutputRecorder.swift

+29-7
Original file line numberDiff line numberDiff line change
@@ -304,18 +304,40 @@ extension Event.ConsoleOutputRecorder {
304304
/// destination.
305305
@discardableResult public func record(_ event: borrowing Event, in context: borrowing Event.Context) -> Bool {
306306
let messages = _humanReadableOutputRecorder.record(event, in: context)
307-
for message in messages {
308-
let symbol = message.symbol?.stringValue(options: options) ?? " "
309307

310-
if case .details = message.symbol, options.useANSIEscapeCodes, options.ansiColorBitDepth > 1 {
308+
// Padding to use in place of a symbol for messages that don't have one.
309+
var padding = " "
310+
#if os(macOS) || (os(iOS) && targetEnvironment(macCatalyst))
311+
if options.useSFSymbols {
312+
padding = " "
313+
}
314+
#endif
315+
316+
let lines = messages.lazy.map { [test = context.test] message in
317+
let symbol = message.symbol?.stringValue(options: options) ?? padding
318+
319+
if case .details = message.symbol {
311320
// Special-case the detail symbol to apply grey to the entire line of
312-
// text instead of just the symbol.
313-
write("\(_ansiEscapeCodePrefix)90m\(symbol) \(message.stringValue)\(_resetANSIEscapeCode)\n")
321+
// text instead of just the symbol. Details may be multi-line messages,
322+
// so split the message on newlines and indent all lines to align them
323+
// to the indentation provided by the symbol.
324+
var lines = message.stringValue.split(whereSeparator: \.isNewline)
325+
lines = CollectionOfOne(lines[0]) + lines.dropFirst().map { line in
326+
"\(padding) \(line)"
327+
}
328+
let stringValue = lines.joined(separator: "\n")
329+
if options.useANSIEscapeCodes, options.ansiColorBitDepth > 1 {
330+
return "\(_ansiEscapeCodePrefix)90m\(symbol) \(stringValue)\(_resetANSIEscapeCode)\n"
331+
} else {
332+
return "\(symbol) \(stringValue)\n"
333+
}
314334
} else {
315-
let colorDots = context.test.map(\.tags).map { self.colorDots(for: $0) } ?? ""
316-
write("\(symbol) \(colorDots)\(message.stringValue)\n")
335+
let colorDots = test.map { self.colorDots(for: $0.tags) } ?? ""
336+
return "\(symbol) \(colorDots)\(message.stringValue)\n"
317337
}
318338
}
339+
340+
write(lines.joined())
319341
return !messages.isEmpty
320342
}
321343

Sources/Testing/Events/Recorder/Event.HumanReadableOutputRecorder.swift

+1-13
Original file line numberDiff line numberDiff line change
@@ -92,19 +92,7 @@ extension Event.HumanReadableOutputRecorder {
9292
/// - Returns: A formatted string representing `comments`, or `nil` if there
9393
/// are none.
9494
private func _formattedComments(_ comments: [Comment]) -> [Message] {
95-
// Insert an arrow character at the start of each comment, then indent any
96-
// additional lines in the comment to align them with the arrow.
97-
comments.lazy
98-
.flatMap { comment in
99-
let lines = comment.rawValue.split(whereSeparator: \.isNewline)
100-
if let firstLine = lines.first {
101-
let remainingLines = lines.dropFirst()
102-
return CollectionOfOne(Message(symbol: .details, stringValue: String(firstLine))) + remainingLines.lazy
103-
.map(String.init)
104-
.map { Message(stringValue: $0) }
105-
}
106-
return []
107-
}
95+
comments.map { Message(symbol: .details, stringValue: $0.rawValue) }
10896
}
10997

11098
/// Get a string representing the comments attached to a test, formatted for

0 commit comments

Comments
 (0)