Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions Sources/Testing/ABI/v0/Encoded/ABIv0.EncodedBacktrace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ extension ABIv0 {
/// This type is not part of the public interface of the testing library. It
/// assists in converting values to JSON; clients that consume this JSON are
/// expected to write their own decoders.
///
/// - Warning: Backtraces are not yet part of the JSON schema.
struct EncodedBacktrace: Sendable {
/// The frames in the backtrace.
var symbolicatedAddresses: [Backtrace.SymbolicatedAddress]
Expand Down
67 changes: 67 additions & 0 deletions Sources/Testing/ABI/v0/Encoded/ABIv0.EncodedError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// 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
//

extension ABIv0 {
/// A type implementing the JSON encoding of ``Error`` for the ABI entry point
/// and event stream output.
///
/// This type is not part of the public interface of the testing library. It
/// assists in converting values to JSON; clients that consume this JSON are
/// expected to write their own decoders.
///
/// - Warning: Errors are not yet part of the JSON schema.
struct EncodedError: Sendable {
/// The error's description
var description: String

/// The domain of the error.
var domain: String

/// The code of the error.
var code: Int

// TODO: userInfo (partial) encoding

init(encoding error: some Error, in eventContext: borrowing Event.Context) {
description = String(describingForTest: error)
domain = error._domain
code = error._code
}
}
}

// MARK: - Error, CustomNSError

extension ABIv0.EncodedError: Error {
var _domain: String {
domain
}

var _code: Int {
code
}

var _userInfo: AnyObject? {
// TODO: userInfo (partial) encoding
nil
}
}

// MARK: - Codable

extension ABIv0.EncodedError: Codable {}

// MARK: - CustomTestStringConvertible

extension ABIv0.EncodedError: CustomTestStringConvertible {
var testDescription: String {
description
}
}
10 changes: 10 additions & 0 deletions Sources/Testing/ABI/v0/Encoded/ABIv0.EncodedIssue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,24 @@ extension ABIv0 {
var sourceLocation: SourceLocation?

/// The backtrace where this issue occurred, if available.
///
/// - Warning: Backtraces are not yet part of the JSON schema.
var _backtrace: EncodedBacktrace?

/// The error associated with this issue, if applicable.
///
/// - Warning: Errors are not yet part of the JSON schema.
var _error: EncodedError?

init(encoding issue: borrowing Issue, in eventContext: borrowing Event.Context) {
isKnown = issue.isKnown
sourceLocation = issue.sourceLocation
if let backtrace = issue.sourceContext.backtrace {
_backtrace = EncodedBacktrace(encoding: backtrace, in: eventContext)
}
if let error = issue.error {
_error = EncodedError(encoding: error, in: eventContext)
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions Sources/Testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ add_library(Testing
ABI/v0/ABIv0.Record+Streaming.swift
ABI/v0/ABIv0.swift
ABI/v0/Encoded/ABIv0.EncodedBacktrace.swift
ABI/v0/Encoded/ABIv0.EncodedError.swift
ABI/v0/Encoded/ABIv0.EncodedEvent.swift
ABI/v0/Encoded/ABIv0.EncodedInstant.swift
ABI/v0/Encoded/ABIv0.EncodedIssue.swift
Expand Down
7 changes: 6 additions & 1 deletion Sources/Testing/ExitTests/ExitTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -505,12 +505,17 @@ extension ExitTest {
let comments: [Comment] = event.messages.compactMap { message in
message.symbol == .details ? Comment(rawValue: message.text) : nil
}
let issueKind: Issue.Kind = if let error = issue._error {
.errorCaught(error)
} else {
.unconditional
}
let sourceContext = SourceContext(
backtrace: nil, // `issue._backtrace` will have the wrong address space.
sourceLocation: issue.sourceLocation
)
// TODO: improve fidelity of issue kind reporting (especially those without associated values)
var issueCopy = Issue(kind: .unconditional, comments: comments, sourceContext: sourceContext)
var issueCopy = Issue(kind: issueKind, comments: comments, sourceContext: sourceContext)
issueCopy.isKnown = issue.isKnown
issueCopy.record()
}
Expand Down
39 changes: 22 additions & 17 deletions Tests/TestingTests/ExitTestTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ private import _TestingInternals
await Task.yield()
exit(123)
}
await #expect(exitsWith: .failure) {
throw MyError()
}
#if !os(Windows)
await #expect(exitsWith: .signal(SIGKILL)) {
_ = kill(getpid(), SIGKILL)
Expand Down Expand Up @@ -203,22 +200,30 @@ private import _TestingInternals

@Test("Exit test forwards issues") func forwardsIssues() async {
await confirmation("Issue recorded") { issueRecorded in
var configuration = Configuration()
configuration.eventHandler = { event, _ in
if case let .issueRecorded(issue) = event.kind,
case .unconditional = issue.kind,
issue.comments.contains("Something went wrong!") {
issueRecorded()
await confirmation("Error caught") { errorCaught in
var configuration = Configuration()
configuration.eventHandler = { event, _ in
guard case let .issueRecorded(issue) = event.kind else {
return
}
if case .unconditional = issue.kind, issue.comments.contains("Something went wrong!") {
issueRecorded()
} else if issue.error != nil {
errorCaught()
}
}
}
configuration.exitTestHandler = ExitTest.handlerForEntryPoint()
configuration.exitTestHandler = ExitTest.handlerForEntryPoint()

await Test {
await #expect(exitsWith: .success) {
#expect(Bool(false), "Something went wrong!")
exit(0)
}
}.run(configuration: configuration)
await Test {
await #expect(exitsWith: .success) {
#expect(Bool(false), "Something went wrong!")
exit(0)
}
await #expect(exitsWith: .failure) {
Issue.record(MyError())
}
}.run(configuration: configuration)
}
}
}

Expand Down