TeraRuntimeResourceTaskTests.swift (3413B)
1 @testable import TeraApp 2 import XCTest 3 4 final class TeraRuntimeResourceTaskTests: XCTestCase { 5 func testCompletedResourceIsCleanedOnceWhenAbandonedBeforeAdoption() async { 6 let cleaned = expectation(description: "Completed but unadopted resource is closed") 7 cleaned.assertForOverFulfill = true 8 let task = TeraRuntimeResourceTask<Int>( 9 deadlineNanoseconds: .max, cleanupDeadlineNanoseconds: .max, 10 operation: { .success(42) }, cleanup: { value in 11 XCTAssertEqual(value, 42) 12 cleaned.fulfill() 13 } 14 ) 15 guard case .completed(.success(42)) = await task.value() else { return XCTFail("Creation must complete") } 16 task.cancel() 17 task.cancel() 18 XCTAssertFalse(task.adopt()) 19 await fulfillment(of: [cleaned], timeout: 2) 20 } 21 22 func testCancellationBeforeCreationCleansLateSuccessOnce() async { 23 let pause = ResourceTestPause() 24 let cleaned = expectation(description: "Late resource is closed") 25 cleaned.assertForOverFulfill = true 26 let task = TeraRuntimeResourceTask<Int>( 27 deadlineNanoseconds: .max, cleanupDeadlineNanoseconds: .max, 28 operation: { await pause.wait(); return .success(42) }, 29 cleanup: { _ in cleaned.fulfill() } 30 ) 31 await pause.entered.wait() 32 task.cancel() 33 task.cancel() 34 guard case .cancelled = await task.value() else { return XCTFail("Caller must stop waiting") } 35 await pause.resume.open() 36 await fulfillment(of: [cleaned], timeout: 2) 37 XCTAssertFalse(task.adopt()) 38 } 39 40 func testTimeoutDuringCreationCleansLateSuccessOnce() async { 41 let pause = ResourceTestPause() 42 let cleaned = expectation(description: "Timed out resource is closed") 43 cleaned.assertForOverFulfill = true 44 let task = TeraRuntimeResourceTask<Int>( 45 deadlineNanoseconds: 1_000_000, cleanupDeadlineNanoseconds: .max, 46 operation: { await pause.wait(); return .success(42) }, 47 cleanup: { _ in cleaned.fulfill() } 48 ) 49 await pause.entered.wait() 50 guard case .timedOut = await task.value() else { return XCTFail("Deadline must end the wait") } 51 task.cancel() 52 await pause.resume.open() 53 await fulfillment(of: [cleaned], timeout: 2) 54 XCTAssertFalse(task.adopt()) 55 } 56 57 func testAdoptedResourceCannotBeCleanedByAnOldWaiter() async { 58 let task = TeraRuntimeResourceTask<Int>( 59 deadlineNanoseconds: .max, cleanupDeadlineNanoseconds: .max, 60 operation: { .success(42) }, cleanup: { _ in XCTFail("The active owner holds this resource") } 61 ) 62 guard case .completed(.success(42)) = await task.value() else { return XCTFail("Creation must complete") } 63 XCTAssertTrue(task.adopt()) 64 XCTAssertFalse(task.adopt()) 65 task.cancel() 66 task.cancel() 67 guard case .completed(.success(42)) = await task.value() else { return XCTFail("Keep the useful result") } 68 } 69 70 func testCreationFailureHasNoResourceToClean() async { 71 let failure = TeraRuntimeFailure.local(operation: "test", code: "test.failure", safeMessage: "Test failure") 72 let task = TeraRuntimeResourceTask<Int>( 73 deadlineNanoseconds: .max, cleanupDeadlineNanoseconds: .max, 74 operation: { .failure(failure) }, cleanup: { _ in XCTFail("No resource was created") } 75 ) 76 guard case let .completed(.failure(observed)) = await task.value() else { return XCTFail("Failure must survive") } 77 XCTAssertEqual(observed, failure) 78 task.cancel() 79 XCTAssertFalse(task.adopt()) 80 } 81 }