1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -Xfrontend -disable-dynamic-actor-isolation -swift-version 6 -g -import-objc-header %S/Inputs/RunOnMainActor.h %import-libdispatch )
// REQUIRES: executable_test
// REQUIRES: concurrency
// REQUIRES: concurrency_runtime
// REQUIRES: libdispatch
// REQUIRES: asserts
// UNSUPPORTED: freestanding
// For now we do not support back deployment or use os stdlib
// UNSUPPORTED: back_deployment_concurrency
// UNSUPPORTED: use_os_stdlib
import StdlibUnittest
import Dispatch
// MARK: Test runOnMainActor in all modes. We use the one future proof API in
// dispatch: dispatch_assert_queue.
////////////////////////
// MARK: Declarations //
////////////////////////
@_silgen_name("dispatch_assert_queue")
func dispatch_assertQueue(_ ptr: UnsafeRawPointer)
func checkIfOnMainQueue() {
dispatch_assertQueue(getDispatchMain())
}
actor Custom {
}
@globalActor
struct CustomActor {
static var shared: Custom {
return Custom()
}
}
/////////////////
// MARK: Tests //
/////////////////
let tests = TestSuite("RunOnMainActor")
tests.test("checkIfOnMainQueue does not crash on the main queue") { @MainActor () -> () in
// Why do we crash if this is synchronous.
expectCrashLater()
checkIfOnMainQueue()
}
tests.test("checkIfOnMainQueue does not crash on the main queue") { @MainActor () async -> () in
checkIfOnMainQueue()
}
tests.test("checkIfOnMainQueue crashes off the main queue") {
expectCrashLater()
await { @CustomActor in
print("=> checkIfOnMainQueue crashes off the main queue")
checkIfOnMainQueue()
}()
}
tests.test("checkIfOnMainQueue crashes off the main queue 2") { @CustomActor () async -> () in
expectCrashLater()
print("=> checkIfOnMainQueue crashes off the main queue 2")
checkIfOnMainQueue()
}
tests.test("checkIfOnMainQueue crashes using pure dispatch queue") { @CustomActor () async -> () in
expectCrashLater()
let queue = DispatchQueue(label: "")
await withCheckedContinuation { cont in
queue.async {
checkIfOnMainQueue()
cont.resume()
}
}
}
tests.test("RunOnMainActor on MainActor") { @MainActor () async -> () in
// This is main actor isolated.
_taskRunOnMainActor { @MainActor in
print("=> RunOnMainActor on MainActor")
checkIfOnMainQueue()
}
}
tests.test("RunOnMainActor off MainActor") {
await { @CustomActor in
_taskRunOnMainActor { @MainActor in
print("=> RunOnMainActor off MainActor")
checkIfOnMainQueue()
}
}()
}
tests.test("RunOnMainActor off MainActor 2") { @CustomActor () async -> () in
_taskRunOnMainActor {
print("=> RunOnMainActor off MainActor 2")
checkIfOnMainQueue()
}
}
// This succeeds since assert understands that a child queue runs on the main
// queue.
tests.test("checkIfOnMainQueue in SubQueue from MainActor") { @CustomActor () async -> () in
let childQueue = DispatchQueue.init(label: "", qos: .background, attributes: [], autoreleaseFrequency: .inherit, target: DispatchQueue.main)
print("=> checkIfOnMainQueue in SubQueue from MainActor start!")
// We cannot use the checked continuation, since we are not going to come back
// to the custom actor.
await withCheckedContinuation { cont in
childQueue.async {
print("=> checkIfOnMainQueue in SubQueue from MainActor")
checkIfOnMainQueue()
cont.resume()
}
}
}
// This should not fail when backwards deployed since we use the backwards
// compatibility trick.
tests.test("taskRunOnMainActor in SubQueue from MainActor") { @CustomActor () async -> () in
let childQueue = DispatchQueue.init(label: "", qos: .background, attributes: [], autoreleaseFrequency: .inherit, target: DispatchQueue.main)
await withCheckedContinuation { cont in
childQueue.async {
_taskRunOnMainActor { @MainActor () -> () in
print("=> taskRunOnMainActor in SubQueue from MainActor")
checkIfOnMainQueue()
cont.resume()
}
}
}
}
tests.test("taskRunOnMainActor in SubQueue off MainActor") { @CustomActor () async -> () in
let d = DispatchQueue.init(label: "", qos: .background)
let childQueue = DispatchQueue.init(label: "", qos: .background, attributes: [], autoreleaseFrequency: .inherit, target: d)
await withCheckedContinuation { cont in
childQueue.async {
_taskRunOnMainActor { @MainActor in
print("=> taskRunOnMainActor in SubQueue from MainActor")
checkIfOnMainQueue()
cont.resume()
}
}
}
}
await runAllTestsAsync()
|