Skip to content

Instantly share code, notes, and snippets.

@jubishop
Last active November 27, 2024 08:43
Show Gist options
  • Save jubishop/695f6938a5d673b2f973e8d6ae0d28ef to your computer and use it in GitHub Desktop.
Save jubishop/695f6938a5d673b2f973e8d6ae0d28ef to your computer and use it in GitHub Desktop.
expect() testing
// Copyright Justin Bishop, 2024
import Foundation
import Testing
public actor Fulfillment {
private var _fulfilled: Bool = false
public func callAsFunction() {
_fulfilled = true
}
}
private extension Fulfillment {
var fulfilled: Bool {
_fulfilled
}
func reset() {
_fulfilled = false
}
}
// This can be used two ways:
// ```
// let fulfilled = Fulfillment()
// await somethingDelayed() {
// await fulfilled()
// }
// await expect("Something delayed", is: fulfilled, in: .milliseconds(100))
// ```
// The passed in `fulfilled` object will be automatically reset for reuse.
//
// Or:
// ```
// await expect("Something delayed", in: .milliseconds(100)) { fulfilled in
// await somethingDelayed() {
// await fulfilled()
// }
// }
// ```
//
// Note:
// `in:` parameter is optional, defaults to .milliseconds(100)
public func expect(
_ comment: Comment,
is fulfillment: Fulfillment? = nil,
in timeout: Duration = .milliseconds(100),
_ block: ((Fulfillment) async throws -> Void)? = nil
) async {
guard fulfillment != nil || block != nil else {
Issue.record(
"""
Fulfillment of \"\(comment)\" cannot be tested: \
either a trailing closure or Fulfillment variable must be provided.
"""
)
return
}
let actualFulfillment = fulfillment ?? Fulfillment()
if let block = block {
do {
try await block(actualFulfillment)
} catch {
Issue.record("Fulfillment of \"\(comment)\" threw error: \(error)")
return
}
}
let startTime = ContinuousClock.now
var timeElapsed = Duration.zero
while timeElapsed <= timeout {
if await actualFulfillment.fulfilled {
await actualFulfillment.reset()
return
}
timeElapsed = ContinuousClock.now - startTime
try! await Task.sleep(for: .milliseconds(10))
}
Issue.record("Expected fulfillment of: \"\(comment)\" never occurred")
}
import Foundation
import Testing
@testable import PodHaven
@Suite("of DownloadManager tests")
class DownloadManagerTests {
@Test("that a single download works successfully")
func singleSuccessfulDownload() async {
let url = URL(string: "https://example.com/data")!
let expectedData = "Test data".data(using: .utf8)!
MockURLProtocol.requestHandler = { request in
#expect(request.url == url, "URL Requested should be what was added")
let response = try #require(
HTTPURLResponse(
url: url,
statusCode: 200,
httpVersion: nil,
headerFields: nil
)
)
return (response, expectedData)
}
let configuration = URLSessionConfiguration.ephemeral
configuration.protocolClasses = [MockURLProtocol.self]
let session = URLSession(configuration: configuration)
let downloadManager = DownloadManager(
session: session,
maxConcurrentDownloads: 2
)
await expect("Single download handler") { fulfilled in
await downloadManager.addURL(url) { result in
switch result {
case .success(let data):
#expect(data == expectedData, "Returned data should match")
await fulfilled()
case .failure(let error):
Issue.record("Expected success, got error: \(error)")
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment