Skip to content

Commit db99f39

Browse files
authored
Remove some legacy Darwin-only code from Test.Clock. (#1606)
This PR removes some more Darwin-only legacy code from the clock implementation. Our minimum deployment target is now high enough that this code is no longer needed. ### 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 f8406de commit db99f39

File tree

16 files changed

+87
-246
lines changed

16 files changed

+87
-246
lines changed

Documentation/Porting.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ Once the header is included, we can call `GetDateTime()` from `Clock.swift`:
116116
+ var seconds = CUnsignedLong(0)
117117
+ GetDateTime(&seconds)
118118
+ seconds -= 2_082_844_800 // seconds between epochs
119-
+ return TimeValue((seconds: Int64(seconds), attoseconds: 0))
119+
+ return TimeValue(rawValue: .seconds(seconds))
120120
#else
121121
#warning("Platform-specific implementation missing: UTC time unavailable (no timespec)")
122122
#endif

Sources/Overlays/_Testing_Foundation/Events/Clock+Date.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ extension Date {
2424
/// of ``Test/Clock/Instant`` to `SuspendingClock.Instant` instead of `Date`.
2525
@_spi(Experimental) @_spi(ForToolsIntegrationOnly)
2626
public init(_ testClockInstant: Test.Clock.Instant) {
27-
let components = testClockInstant.timeComponentsSince1970
28-
let secondsSince1970 = TimeInterval(components.seconds) + (TimeInterval(components.attoseconds) / TimeInterval(1_000_000_000_000_000_000))
29-
self.init(timeIntervalSince1970: secondsSince1970)
27+
self.init(timeIntervalSince1970: testClockInstant.durationSince1970 / .seconds(1))
3028
}
3129
}
3230
#endif

Sources/Testing/ABI/Encoded/ABI.EncodedInstant.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ extension ABI {
2525
var since1970: Double
2626

2727
init(encoding instant: borrowing Test.Clock.Instant) {
28-
absolute = Double(instant.suspending)
28+
absolute = instant.suspending.rawValue / .seconds(1)
2929
#if !SWT_NO_UTC_CLOCK
30-
since1970 = Double(instant.wall)
30+
since1970 = instant.wall.rawValue / .seconds(1)
3131
#else
3232
since1970 = 0
3333
#endif

Sources/Testing/ABI/Encoded/ABI.EncodedTest.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,7 @@ extension ABI {
131131
if !bugs.isEmpty {
132132
self.bugs = bugs
133133
}
134-
self.timeLimit = test.timeLimit
135-
.map(TimeValue.init)
136-
.map(Double.init)
134+
self.timeLimit = test.timeLimit.map { $0 / .seconds(1) }
137135
}
138136
}
139137
}

Sources/Testing/Events/Clock.swift

Lines changed: 26 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ extension Test {
2121
/// An instant on the testing clock.
2222
public struct Instant: Sendable {
2323
/// The suspending-clock time corresponding to this instant.
24-
fileprivate(set) var suspending = TimeValue(SuspendingClock.Instant.now)
24+
fileprivate(set) var suspending = TimeValue(rawValue: SuspendingClock().systemEpoch.duration(to: .now))
2525

2626
#if !SWT_NO_UTC_CLOCK
2727
/// The wall-clock time corresponding to this instant.
@@ -35,10 +35,10 @@ extension Test {
3535
#else
3636
timespec_get(&wall, TIME_UTC)
3737
#endif
38-
return TimeValue(wall)
38+
return TimeValue(rawValue: .seconds(wall.tv_sec) + .nanoseconds(wall.tv_nsec))
3939
#else
4040
#warning("Platform-specific implementation missing: UTC time unavailable (no timespec)")
41-
return TimeValue((0, 0))
41+
return TimeValue(rawValue: .zero)
4242
#endif
4343
}()
4444
#endif
@@ -63,52 +63,32 @@ extension SuspendingClock.Instant {
6363
/// - Parameters:
6464
/// - testClockInstant: The equivalent instant on ``Test/Clock``.
6565
public init(_ testClockInstant: Test.Clock.Instant) {
66-
self.init(testClockInstant.suspending)
66+
self = SuspendingClock().systemEpoch + testClockInstant.suspending.rawValue
6767
}
6868
}
6969

70-
extension Test.Clock.Instant {
7170
#if !SWT_NO_UTC_CLOCK
72-
/// The duration since 1970 represented by this instance as a tuple of seconds
73-
/// and attoseconds.
74-
///
75-
/// The value of this property is the equivalent of `self` on the wall clock.
76-
/// It is suitable for display to the user, but not for fine timing
77-
/// calculations.
78-
public var timeComponentsSince1970: (seconds: Int64, attoseconds: Int64) {
79-
wall.components
80-
}
81-
71+
extension Test.Clock.Instant {
8272
/// The duration since 1970 represented by this instance.
8373
///
84-
/// The value of this property is the equivalent of `self` on the wall clock.
85-
/// It is suitable for display to the user, but not for fine timing
86-
/// calculations.
87-
public var durationSince1970: Duration {
88-
Duration(wall)
74+
/// The Foundation overlay uses this property to implement `Date.init(_:)`.
75+
package var durationSince1970: Duration {
76+
wall.rawValue
8977
}
78+
}
9079
#endif
9180

92-
/// Get the number of nanoseconds from this instance to another.
93-
///
94-
/// - Parameters:
95-
/// - other: The later instant.
96-
///
97-
/// - Returns: The number of nanoseconds between `self` and `other`. If
98-
/// `other` is ordered before this instance, the result is negative.
99-
func nanoseconds(until other: Self) -> Int64 {
100-
if other < self {
101-
return -other.nanoseconds(until: self)
102-
}
103-
let otherNanoseconds = (other.suspending.seconds * 1_000_000_000) + (other.suspending.attoseconds / 1_000_000_000)
104-
let selfNanoseconds = (suspending.seconds * 1_000_000_000) + (suspending.attoseconds / 1_000_000_000)
105-
return otherNanoseconds - selfNanoseconds
81+
// MARK: - Clock
82+
83+
extension Test.Clock: _Concurrency.Clock {
84+
public var now: Instant {
85+
.now
10686
}
107-
}
10887

109-
// MARK: - Sleeping
88+
public var minimumResolution: Duration {
89+
SuspendingClock().minimumResolution
90+
}
11091

111-
extension Test.Clock {
11292
/// Suspend the current task for the given duration.
11393
///
11494
/// - Parameters:
@@ -124,35 +104,14 @@ extension Test.Clock {
124104
#if !SWT_NO_UNSTRUCTURED_TASKS
125105
return try await SuspendingClock().sleep(for: duration)
126106
#elseif !SWT_NO_TIMESPEC
127-
let timeValue = TimeValue(duration)
128-
var ts = timespec(timeValue)
107+
var ts = timespec(tv_sec: .init(duration.components.seconds), tv_nsec: .init(duration.components.attoseconds / 1_000_000_000))
129108
var tsRemaining = ts
130109
while 0 != nanosleep(&ts, &tsRemaining) {
131110
try Task.checkCancellation()
132111
ts = tsRemaining
133112
}
134113
#else
135114
#warning("Platform-specific implementation missing: task sleep unavailable")
136-
#endif
137-
}
138-
}
139-
140-
// MARK: - Clock
141-
142-
extension Test.Clock: _Concurrency.Clock {
143-
public typealias Duration = SuspendingClock.Duration
144-
145-
public var now: Instant {
146-
.now
147-
}
148-
149-
public var minimumResolution: Duration {
150-
#if SWT_TARGET_OS_APPLE
151-
var res = timespec()
152-
_ = clock_getres(CLOCK_UPTIME_RAW, &res)
153-
return Duration(TimeValue(res))
154-
#else
155-
SuspendingClock().minimumResolution
156115
#endif
157116
}
158117

@@ -170,59 +129,39 @@ extension Test.Clock: _Concurrency.Clock {
170129

171130
extension Test.Clock.Instant: Equatable, Hashable, Comparable {
172131
public static func ==(lhs: Self, rhs: Self) -> Bool {
173-
lhs.suspending == rhs.suspending
132+
lhs.suspending.rawValue == rhs.suspending.rawValue
174133
}
175134

176135
public func hash(into hasher: inout Hasher) {
177-
hasher.combine(suspending)
136+
hasher.combine(suspending.rawValue)
178137
}
179138

180139
public static func <(lhs: Self, rhs: Self) -> Bool {
181-
lhs.suspending < rhs.suspending
140+
lhs.suspending.rawValue < rhs.suspending.rawValue
182141
}
183142
}
184143

185144
// MARK: - InstantProtocol
186145

187146
extension Test.Clock.Instant: InstantProtocol {
188-
public typealias Duration = Swift.Duration
189-
190147
public func advanced(by duration: Duration) -> Self {
191148
var result = self
192149

193-
result.suspending = TimeValue(Duration(result.suspending) + duration)
150+
result.suspending = TimeValue(rawValue: result.suspending.rawValue + duration)
194151
#if !SWT_NO_UTC_CLOCK
195-
result.wall = TimeValue(Duration(result.wall) + duration)
152+
result.wall = TimeValue(rawValue: result.wall.rawValue + duration)
196153
#endif
197154

198155
return result
199156
}
200157

201158
public func duration(to other: Test.Clock.Instant) -> Duration {
202-
Duration(other.suspending) - Duration(suspending)
203-
}
204-
}
205-
206-
// MARK: - Duration descriptions
207-
208-
extension Test.Clock.Instant {
209-
/// Get a description of the duration between this instance and another.
210-
///
211-
/// - Parameters:
212-
/// - other: The later instant.
213-
///
214-
/// - Returns: A string describing the duration between `self` and `other`,
215-
/// up to millisecond accuracy.
216-
func descriptionOfDuration(to other: Test.Clock.Instant) -> String {
217-
#if SWT_TARGET_OS_APPLE
218-
let (seconds, nanosecondsRemaining) = nanoseconds(until: other).quotientAndRemainder(dividingBy: 1_000_000_000)
219-
return String(describing: TimeValue((seconds, nanosecondsRemaining * 1_000_000_000)))
220-
#else
221-
return String(describing: TimeValue(Duration(other.suspending) - Duration(suspending)))
222-
#endif
159+
other.suspending.rawValue - suspending.rawValue
223160
}
224161
}
225162

163+
#if !SWT_NO_SNAPSHOT_TYPES
226164
// MARK: - Codable
227165

228166
extension Test.Clock.Instant: Codable {}
167+
#endif

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,11 @@ extension Event.HumanReadableOutputRecorder {
360360
}
361361
}
362362

363+
// A helper function for displaying test durations.
364+
func descriptionOfDuration(from start: Test.Clock.Instant, to end: Test.Clock.Instant) -> String {
365+
String(describing: TimeValue(rawValue: end.suspending.rawValue - start.suspending.rawValue))
366+
}
367+
363368
// Finally, produce any messages for the event.
364369
switch event.kind {
365370
case .testDiscovered:
@@ -429,7 +434,7 @@ extension Event.HumanReadableOutputRecorder {
429434
let testDataGraph = context.testData.subgraph(at: keyPath)
430435
let testData = testDataGraph?.value ?? .init(startInstant: instant)
431436
let issues = _issueCounts(in: testDataGraph)
432-
let duration = testData.startInstant.descriptionOfDuration(to: instant)
437+
let duration = descriptionOfDuration(from: testData.startInstant, to: instant)
433438
let testCasesCount = if test.isParameterized, let testDataGraph {
434439
" with \(testDataGraph.children.count.counting("test case"))"
435440
} else {
@@ -579,7 +584,7 @@ extension Event.HumanReadableOutputRecorder {
579584
let testDataGraph = context.testData.subgraph(at: keyPath)
580585
let testData = testDataGraph?.value ?? .init(startInstant: instant)
581586
let issues = _issueCounts(in: testDataGraph)
582-
let duration = testData.startInstant.descriptionOfDuration(to: instant)
587+
let duration = descriptionOfDuration(from: testData.startInstant, to: instant)
583588

584589
var cancellationComment = "."
585590
let (symbol, verbed): (Event.Symbol, String)
@@ -608,7 +613,7 @@ extension Event.HumanReadableOutputRecorder {
608613
guard let iterationStartInstant = context.iterationStartInstant else {
609614
break
610615
}
611-
let duration = iterationStartInstant.descriptionOfDuration(to: instant)
616+
let duration = descriptionOfDuration(from: iterationStartInstant, to: instant)
612617

613618
return [
614619
Message(
@@ -622,7 +627,7 @@ extension Event.HumanReadableOutputRecorder {
622627
let suiteCount = context.suiteCount
623628
let issues = _issueCounts(in: context.testData)
624629
let runStartInstant = context.runStartInstant ?? instant
625-
let duration = runStartInstant.descriptionOfDuration(to: instant)
630+
let duration = descriptionOfDuration(from: runStartInstant, to: instant)
626631

627632
return if issues.errorIssueCount > 0 {
628633
[

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ extension Event.JUnitXMLRecorder {
148148
let skipCount = context.testData
149149
.compactMap(\.value?.skipInfo)
150150
.count
151-
let durationNanoseconds = context.runStartInstant.map { $0.nanoseconds(until: instant) } ?? 0
152-
let durationSeconds = Double(durationNanoseconds) / 1_000_000_000
151+
let durationSeconds = context.runStartInstant
152+
.map { (instant.suspending.rawValue - $0.suspending.rawValue) / .seconds(1) } ?? 0.0
153153
return #"""
154154
<testsuite name="TestResults" errors="0" tests="\#(context.testCount)" failures="\#(issueCount)" skipped="\#(skipCount)" time="\#(durationSeconds)">
155155
\#(Self._xml(for: context.testData))
@@ -185,8 +185,7 @@ extension Event.JUnitXMLRecorder {
185185
// an end instant; don't report timing for such tests.
186186
var timeClause = ""
187187
if let endInstant = testData.endInstant {
188-
let durationNanoseconds = testData.startInstant.nanoseconds(until: endInstant)
189-
let durationSeconds = Double(durationNanoseconds) / 1_000_000_000
188+
let durationSeconds = (endInstant.suspending.rawValue - testData.startInstant.suspending.rawValue) / .seconds(1)
190189
timeClause = #"time="\#(durationSeconds)" "#
191190
}
192191

0 commit comments

Comments
 (0)