Skip to content

Commit

Permalink
MainActor Store Isolation (#3277)
Browse files Browse the repository at this point in the history
* `@preconcurrency @MainActor` isolation of `Store`

* Remove unneeded `@MainActor`s

* Remove thread checking code

* Remove unneeded `@MainActor`s

* Swift 5.10 compatibility fixes

* wip

* More 5.10 fixes

* wip

* fixes

* wip

* wip

* up the timeout

* wip

* Fixes

* Remove mainActorASAP in favor of mainActorNow. (#3288)

* wip

* Run swift-format

* Update README.md

* Fix integration tests. (#3294)

* Fix integration tests.

* wip

* wip

* Run swift-format

* mainActorNow doesnt need escaping closure

* wip

* migration guide

* wip

* Update MigratingTo1.14.md

---------

Co-authored-by: Brandon Williams <mbrandonw@hey.com>
Co-authored-by: Brandon Williams <135203+mbrandonw@users.noreply.github.com>
Co-authored-by: mbrandonw <mbrandonw@users.noreply.github.com>
  • Loading branch information
4 people authored Aug 27, 2024
1 parent f02fab5 commit 08faf84
Show file tree
Hide file tree
Showing 230 changed files with 719 additions and 1,368 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-dependencies",
"state" : {
"revision" : "d7472be6b3c89251ce4c0db07d32405b43426781",
"version" : "1.3.7"
"revision" : "21660b042cd8fd0bdd45cc39050cacd4e91a63a4",
"version" : "1.3.8"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,19 +241,19 @@ extension WebSocketClient: DependencyKey {
sendPing: { try await WebSocketActor.shared.sendPing(id: $0) }
)

final actor WebSocketActor: GlobalActor {
final class Delegate: NSObject, URLSessionWebSocketDelegate {
@globalActor final actor WebSocketActor {
private final class Delegate: NSObject, @unchecked Sendable, URLSessionWebSocketDelegate {
var continuation: AsyncStream<Action>.Continuation?

func urlSession(
nonisolated func urlSession(
_: URLSession,
webSocketTask _: URLSessionWebSocketTask,
didOpenWithProtocol protocol: String?
) {
self.continuation?.yield(.didOpen(protocol: `protocol`))
}

func urlSession(
nonisolated func urlSession(
_: URLSession,
webSocketTask _: URLSessionWebSocketTask,
didCloseWith closeCode: URLSessionWebSocketTask.CloseCode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import XCTest
@testable import SwiftUICaseStudies

final class AlertsAndConfirmationDialogsTests: XCTestCase {
@MainActor
func testAlert() async {
let store = TestStore(initialState: AlertAndConfirmationDialog.State()) {
let store = await TestStore(initialState: AlertAndConfirmationDialog.State()) {
AlertAndConfirmationDialog()
}

Expand All @@ -33,9 +32,8 @@ final class AlertsAndConfirmationDialogsTests: XCTestCase {
}
}

@MainActor
func testConfirmationDialog() async {
let store = TestStore(initialState: AlertAndConfirmationDialog.State()) {
let store = await TestStore(initialState: AlertAndConfirmationDialog.State()) {
AlertAndConfirmationDialog()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import XCTest
@testable import SwiftUICaseStudies

final class AnimationTests: XCTestCase {
@MainActor
func testRainbow() async {
let clock = TestClock()

let store = TestStore(initialState: Animations.State()) {
let store = await TestStore(initialState: Animations.State()) {
Animations()
} withDependencies: {
$0.continuousClock = clock
Expand Down Expand Up @@ -58,11 +57,10 @@ final class AnimationTests: XCTestCase {
await clock.run()
}

@MainActor
func testReset() async {
let clock = TestClock()

let store = TestStore(initialState: Animations.State()) {
let store = await TestStore(initialState: Animations.State()) {
Animations()
} withDependencies: {
$0.continuousClock = clock
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import XCTest
@testable import SwiftUICaseStudies

final class BindingFormTests: XCTestCase {
@MainActor
func testBasics() async {
let store = TestStore(initialState: BindingForm.State()) {
let store = await TestStore(initialState: BindingForm.State()) {
BindingForm()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import XCTest
@testable import SwiftUICaseStudies

final class SharedStateFileStorageTests: XCTestCase {
@MainActor
func testTabSelection() async {
let store = TestStore(initialState: SharedStateFileStorage.State()) {
let store = await TestStore(initialState: SharedStateFileStorage.State()) {
SharedStateFileStorage()
}

Expand All @@ -18,9 +17,8 @@ final class SharedStateFileStorageTests: XCTestCase {
}
}

@MainActor
func testSharedCounts() async {
let store = TestStore(initialState: SharedStateFileStorage.State()) {
let store = await TestStore(initialState: SharedStateFileStorage.State()) {
SharedStateFileStorage()
}

Expand All @@ -37,9 +35,8 @@ final class SharedStateFileStorageTests: XCTestCase {
}
}

@MainActor
func testAlert() async {
let store = TestStore(initialState: SharedStateFileStorage.State()) {
let store = await TestStore(initialState: SharedStateFileStorage.State()) {
SharedStateFileStorage()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import XCTest
@testable import SwiftUICaseStudies

final class SharedStateInMemoryTests: XCTestCase {
@MainActor
func testTabSelection() async {
let store = TestStore(initialState: SharedStateInMemory.State()) {
let store = await TestStore(initialState: SharedStateInMemory.State()) {
SharedStateInMemory()
}

Expand All @@ -18,9 +17,8 @@ final class SharedStateInMemoryTests: XCTestCase {
}
}

@MainActor
func testSharedCounts() async {
let store = TestStore(initialState: SharedStateInMemory.State()) {
let store = await TestStore(initialState: SharedStateInMemory.State()) {
SharedStateInMemory()
}

Expand All @@ -37,9 +35,8 @@ final class SharedStateInMemoryTests: XCTestCase {
}
}

@MainActor
func testAlert() async {
let store = TestStore(initialState: SharedStateInMemory.State()) {
let store = await TestStore(initialState: SharedStateInMemory.State()) {
SharedStateInMemory()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import XCTest
@testable import SwiftUICaseStudies

final class SharedStateUserDefaultsTests: XCTestCase {
@MainActor
func testTabSelection() async {
let store = TestStore(initialState: SharedStateUserDefaults.State()) {
let store = await TestStore(initialState: SharedStateUserDefaults.State()) {
SharedStateUserDefaults()
}

Expand All @@ -18,9 +17,8 @@ final class SharedStateUserDefaultsTests: XCTestCase {
}
}

@MainActor
func testSharedCounts() async {
let store = TestStore(initialState: SharedStateUserDefaults.State()) {
let store = await TestStore(initialState: SharedStateUserDefaults.State()) {
SharedStateUserDefaults()
}

Expand All @@ -37,9 +35,8 @@ final class SharedStateUserDefaultsTests: XCTestCase {
}
}

@MainActor
func testAlert() async {
let store = TestStore(initialState: SharedStateUserDefaults.State()) {
let store = await TestStore(initialState: SharedStateUserDefaults.State()) {
SharedStateUserDefaults()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import XCTest
@testable import SwiftUICaseStudies

final class EffectsBasicsTests: XCTestCase {
@MainActor
func testCountDown() async {
let store = TestStore(initialState: EffectsBasics.State()) {
let store = await TestStore(initialState: EffectsBasics.State()) {
EffectsBasics()
} withDependencies: {
$0.continuousClock = ImmediateClock()
Expand All @@ -20,9 +19,8 @@ final class EffectsBasicsTests: XCTestCase {
}
}

@MainActor
func testNumberFact() async {
let store = TestStore(initialState: EffectsBasics.State()) {
let store = await TestStore(initialState: EffectsBasics.State()) {
EffectsBasics()
} withDependencies: {
$0.factClient.fetch = { "\($0) is a good number Brent" }
Expand All @@ -41,9 +39,8 @@ final class EffectsBasicsTests: XCTestCase {
}
}

@MainActor
func testDecrement() async {
let store = TestStore(initialState: EffectsBasics.State()) {
let store = await TestStore(initialState: EffectsBasics.State()) {
EffectsBasics()
} withDependencies: {
$0.continuousClock = ImmediateClock()
Expand All @@ -57,9 +54,8 @@ final class EffectsBasicsTests: XCTestCase {
}
}

@MainActor
func testDecrementCancellation() async {
let store = TestStore(initialState: EffectsBasics.State()) {
let store = await TestStore(initialState: EffectsBasics.State()) {
EffectsBasics()
} withDependencies: {
$0.continuousClock = TestClock()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import XCTest
@testable import SwiftUICaseStudies

final class EffectsCancellationTests: XCTestCase {
@MainActor
func testTrivia_SuccessfulRequest() async {
let store = TestStore(initialState: EffectsCancellation.State()) {
let store = await TestStore(initialState: EffectsCancellation.State()) {
EffectsCancellation()
} withDependencies: {
$0.factClient.fetch = { "\($0) is a good number Brent" }
Expand All @@ -27,10 +26,9 @@ final class EffectsCancellationTests: XCTestCase {
}
}

@MainActor
func testTrivia_FailedRequest() async {
struct FactError: Equatable, Error {}
let store = TestStore(initialState: EffectsCancellation.State()) {
let store = await TestStore(initialState: EffectsCancellation.State()) {
EffectsCancellation()
} withDependencies: {
$0.factClient.fetch = { _ in throw FactError() }
Expand All @@ -50,9 +48,8 @@ final class EffectsCancellationTests: XCTestCase {
// in the `.cancelButtonTapped` action of the `effectsCancellationReducer`. This will cause the
// test to fail, showing that we are exhaustively asserting that the effect truly is canceled and
// will never emit.
@MainActor
func testTrivia_CancelButtonCancelsRequest() async {
let store = TestStore(initialState: EffectsCancellation.State()) {
let store = await TestStore(initialState: EffectsCancellation.State()) {
EffectsCancellation()
} withDependencies: {
$0.factClient.fetch = { _ in try await Task.never() }
Expand All @@ -66,9 +63,8 @@ final class EffectsCancellationTests: XCTestCase {
}
}

@MainActor
func testTrivia_PlusMinusButtonsCancelsRequest() async {
let store = TestStore(initialState: EffectsCancellation.State()) {
let store = await TestStore(initialState: EffectsCancellation.State()) {
EffectsCancellation()
} withDependencies: {
$0.factClient.fetch = { _ in try await Task.never() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import XCTest
@testable import SwiftUICaseStudies

final class LongLivingEffectsTests: XCTestCase {
@MainActor
func testReducer() async {
let (screenshots, takeScreenshot) = AsyncStream.makeStream(of: Void.self)

let store = TestStore(initialState: LongLivingEffects.State()) {
let store = await TestStore(initialState: LongLivingEffects.State()) {
LongLivingEffects()
} withDependencies: {
$0.screenshots = { screenshots }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import XCTest
@testable import SwiftUICaseStudies

final class RefreshableTests: XCTestCase {
@MainActor
func testHappyPath() async {
let store = TestStore(initialState: Refreshable.State()) {
let store = await TestStore(initialState: Refreshable.State()) {
Refreshable()
} withDependencies: {
$0.factClient.fetch = { "\($0) is a good number." }
Expand All @@ -22,11 +21,10 @@ final class RefreshableTests: XCTestCase {
}
}

@MainActor
func testUnhappyPath() async {
struct FactError: Equatable, Error {}

let store = TestStore(initialState: Refreshable.State()) {
let store = await TestStore(initialState: Refreshable.State()) {
Refreshable()
} withDependencies: {
$0.factClient.fetch = { _ in throw FactError() }
Expand All @@ -40,9 +38,8 @@ final class RefreshableTests: XCTestCase {
await store.receive(\.factResponse.failure)
}

@MainActor
func testCancellation() async {
let store = TestStore(initialState: Refreshable.State()) {
let store = await TestStore(initialState: Refreshable.State()) {
Refreshable()
} withDependencies: {
$0.factClient.fetch = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import XCTest
@testable import SwiftUICaseStudies

final class TimersTests: XCTestCase {
@MainActor
func testStart() async {
let clock = TestClock()

let store = TestStore(initialState: Timers.State()) {
let store = await TestStore(initialState: Timers.State()) {
Timers()
} withDependencies: {
$0.continuousClock = clock
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import XCTest
@testable import SwiftUICaseStudies

final class WebSocketTests: XCTestCase {
@MainActor
func testWebSocketHappyPath() async {
let actions = AsyncStream.makeStream(of: WebSocketClient.Action.self)
let messages = AsyncStream.makeStream(of: Result<WebSocketClient.Message, Error>.self)

let store = TestStore(initialState: WebSocket.State()) {
let store = await TestStore(initialState: WebSocket.State()) {
WebSocket()
} withDependencies: {
$0.continuousClock = ImmediateClock()
Expand Down Expand Up @@ -56,12 +55,11 @@ final class WebSocketTests: XCTestCase {
await store.finish()
}

@MainActor
func testWebSocketSendFailure() async {
let actions = AsyncStream.makeStream(of: WebSocketClient.Action.self)
let messages = AsyncStream.makeStream(of: Result<WebSocketClient.Message, Error>.self)

let store = TestStore(initialState: WebSocket.State()) {
let store = await TestStore(initialState: WebSocket.State()) {
WebSocket()
} withDependencies: {
$0.continuousClock = ImmediateClock()
Expand Down Expand Up @@ -138,11 +136,10 @@ final class WebSocketTests: XCTestCase {
}
}

@MainActor
func testWebSocketConnectError() async {
let actions = AsyncStream.makeStream(of: WebSocketClient.Action.self)

let store = TestStore(initialState: WebSocket.State()) {
let store = await TestStore(initialState: WebSocket.State()) {
WebSocket()
} withDependencies: {
$0.continuousClock = ImmediateClock()
Expand Down
Loading

0 comments on commit 08faf84

Please sign in to comment.