XCTest+AsyncAwait.swift 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. /*
  2. * Copyright 2021, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #if compiler(>=5.6)
  17. import XCTest
  18. @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
  19. internal func XCTAssertThrowsError<T>(
  20. _ expression: @autoclosure () async throws -> T,
  21. verify: (Error) -> Void = { _ in },
  22. file: StaticString = #file,
  23. line: UInt = #line
  24. ) async {
  25. do {
  26. _ = try await expression()
  27. XCTFail("Expression did not throw error", file: file, line: line)
  28. } catch {
  29. verify(error)
  30. }
  31. }
  32. fileprivate enum TaskResult<Result> {
  33. case operation(Result)
  34. case cancellation
  35. }
  36. @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
  37. func withTaskCancelledAfter<Result>(
  38. nanoseconds: UInt64,
  39. operation: @escaping @Sendable () async -> Result
  40. ) async throws {
  41. try await withThrowingTaskGroup(of: TaskResult<Result>.self) { group in
  42. group.addTask {
  43. return .operation(await operation())
  44. }
  45. group.addTask {
  46. try await Task.sleep(nanoseconds: nanoseconds)
  47. return .cancellation
  48. }
  49. // Only the sleeping task can throw if it's cancelled, in which case we want to throw.
  50. let firstResult = try await group.next()
  51. // A task completed, cancel the rest.
  52. group.cancelAll()
  53. // Check which task completed.
  54. switch firstResult {
  55. case .cancellation:
  56. () // Fine, what we expect.
  57. case .operation:
  58. XCTFail("Operation completed before cancellation")
  59. case .none:
  60. XCTFail("No tasks completed")
  61. }
  62. // Wait for the other task. The operation cannot, only the sleeping task can.
  63. try await group.waitForAll()
  64. }
  65. }
  66. #endif // compiler(>=5.6)