Skip to content

Commit 479718a

Browse files
committed
Use the entire SHA-256 hash as an exit test ID. (#1053)
This PR uses the entire 256 bits of the computed SHA-256 hash for an exit test's ID, not just the first 128. They're there, might as well use them. ### 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 42e688f commit 479718a

File tree

3 files changed

+41
-32
lines changed

3 files changed

+41
-32
lines changed

Diff for: Sources/Testing/ExitTests/ExitTest.swift

+13-9
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,17 @@ public struct ExitTest: Sendable, ~Copyable {
4848
/// Storage for the underlying bits of the ID.
4949
///
5050
/// - Note: On Apple platforms, we deploy to OS versions that do not include
51-
/// support for `UInt128`, so we use two `UInt64`s for storage instead.
52-
private var _lo: UInt64
53-
private var _hi: UInt64
54-
55-
init(_ uuid: (UInt64, UInt64)) {
56-
self._lo = uuid.0
57-
self._hi = uuid.1
51+
/// support for `UInt128`, so we use four `UInt64`s for storage instead.
52+
private var _0: UInt64
53+
private var _1: UInt64
54+
private var _2: UInt64
55+
private var _3: UInt64
56+
57+
init(_ uuid: (UInt64, UInt64, UInt64, UInt64)) {
58+
self._0 = uuid.0
59+
self._1 = uuid.1
60+
self._2 = uuid.2
61+
self._3 = uuid.3
5862
}
5963
}
6064

@@ -270,7 +274,7 @@ extension ExitTest: DiscoverableAsTestContent {
270274
/// - Warning: This function is used to implement the `#expect(exitsWith:)`
271275
/// macro. Do not use it directly.
272276
public static func __store(
273-
_ id: (UInt64, UInt64),
277+
_ id: (UInt64, UInt64, UInt64, UInt64),
274278
_ body: @escaping @Sendable () async throws -> Void,
275279
into outValue: UnsafeMutableRawPointer,
276280
asTypeAt typeAddress: UnsafeRawPointer,
@@ -344,7 +348,7 @@ extension ExitTest {
344348
/// `await #expect(exitsWith:) { }` invocations regardless of calling
345349
/// convention.
346350
func callExitTest(
347-
identifiedBy exitTestID: (UInt64, UInt64),
351+
identifiedBy exitTestID: (UInt64, UInt64, UInt64, UInt64),
348352
exitsWith expectedExitCondition: ExitTest.Condition,
349353
observing observedValues: [any PartialKeyPath<ExitTest.Result> & Sendable],
350354
expression: __Expression,

Diff for: Sources/Testing/Expectations/ExpectationChecking+Macro.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ public func __checkClosureCall<R>(
11471147
/// `#require()` macros. Do not call it directly.
11481148
@_spi(Experimental)
11491149
public func __checkClosureCall(
1150-
identifiedBy exitTestID: (UInt64, UInt64),
1150+
identifiedBy exitTestID: (UInt64, UInt64, UInt64, UInt64),
11511151
exitsWith expectedExitCondition: ExitTest.Condition,
11521152
observing observedValues: [any PartialKeyPath<ExitTest.Result> & Sendable],
11531153
performing body: @convention(thin) () -> Void,

Diff for: Sources/TestingMacros/ConditionMacro.swift

+27-22
Original file line numberDiff line numberDiff line change
@@ -551,30 +551,35 @@ extension ExitTestConditionMacro {
551551
for macro: some FreestandingMacroExpansionSyntax,
552552
in context: some MacroExpansionContext
553553
) -> ExprSyntax {
554-
let exitTestID: (UInt64, UInt64)
555-
if let sourceLocation = context.location(of: macro, at: .afterLeadingTrivia, filePathMode: .fileID),
556-
let fileID = sourceLocation.file.as(StringLiteralExprSyntax.self)?.representedLiteralValue,
557-
let line = sourceLocation.line.as(IntegerLiteralExprSyntax.self)?.representedLiteralValue,
558-
let column = sourceLocation.column.as(IntegerLiteralExprSyntax.self)?.representedLiteralValue {
559-
// Hash the entire source location and store as many bits as possible in
560-
// the resulting ID.
561-
let stringValue = "\(fileID):\(line):\(column)"
562-
exitTestID = SHA256.hash(stringValue.utf8).withUnsafeBytes { sha256 in
563-
sha256.loadUnaligned(as: (UInt64, UInt64).self)
554+
withUnsafeTemporaryAllocation(of: UInt64.self, capacity: 4) { exitTestID in
555+
if let sourceLocation = context.location(of: macro, at: .afterLeadingTrivia, filePathMode: .fileID),
556+
let fileID = sourceLocation.file.as(StringLiteralExprSyntax.self)?.representedLiteralValue,
557+
let line = sourceLocation.line.as(IntegerLiteralExprSyntax.self)?.representedLiteralValue,
558+
let column = sourceLocation.column.as(IntegerLiteralExprSyntax.self)?.representedLiteralValue {
559+
// Hash the entire source location and store the entire hash in the
560+
// resulting ID.
561+
let stringValue = "\(fileID):\(line):\(column)"
562+
exitTestID.withMemoryRebound(to: UInt8.self) { exitTestID in
563+
_ = exitTestID.initialize(from: SHA256.hash(stringValue.utf8))
564+
}
565+
} else {
566+
// This branch is dead code in production, but is used when we expand a
567+
// macro in our own unit tests because the macro expansion context does
568+
// not have real source location information.
569+
for i in 0 ..< exitTestID.count {
570+
exitTestID[i] = .random(in: 0 ... .max)
571+
}
564572
}
565-
} else {
566-
// This branch is dead code in production, but is used when we expand a
567-
// macro in our own unit tests because the macro expansion context does
568-
// not have real source location information.
569-
exitTestID.0 = .random(in: 0 ... .max)
570-
exitTestID.1 = .random(in: 0 ... .max)
571-
}
572573

573-
// Return a tuple of integer literals (which is what the runtime __store()
574-
// function is expecting.)
575-
return """
576-
(\(IntegerLiteralExprSyntax(exitTestID.0, radix: .hex)), \(IntegerLiteralExprSyntax(exitTestID.1, radix: .hex)))
577-
"""
574+
// Return a tuple of integer literals (which is what the runtime __store()
575+
// function is expecting.)
576+
let tupleExpr = TupleExprSyntax {
577+
for uint64 in exitTestID {
578+
LabeledExprSyntax(expression: IntegerLiteralExprSyntax(uint64, radix: .hex))
579+
}
580+
}
581+
return ExprSyntax(tupleExpr)
582+
}
578583
}
579584
}
580585

0 commit comments

Comments
 (0)