Files
swift-composable-architectu…/Tests/ComposableArchitectureMacrosTests/PresentsMacroTests.swift
Ryan Carver af60ed2d51 Add shouldNotifyObservers to ObservableState (#3751)
* add shouldNotifyObservers support to ObservableState

* update tests

* move shouldNotifyObservers logic into ObservationState

* fix test for macro change

* Fix test

* wip

* update xcode on ci

* wip

* wip

* wip

* wip

---------

Co-authored-by: Brandon Williams <mbrandonw@hey.com>
Co-authored-by: Stephen Celis <stephen@stephencelis.com>
2025-08-18 17:47:27 -07:00

225 lines
7.7 KiB
Swift

#if canImport(ComposableArchitectureMacros)
import ComposableArchitectureMacros
import MacroTesting
import SwiftSyntaxMacros
import SwiftSyntaxMacrosTestSupport
import XCTest
final class PresentsMacroTests: XCTestCase {
override func invokeTest() {
withMacroTesting(
// record: .failed,
macros: [PresentsMacro.self]
) {
super.invokeTest()
}
}
func testBasics() {
assertMacro {
"""
struct State {
@Presents var destination: Destination.State?
}
"""
} expansion: {
#"""
struct State {
var destination: Destination.State? {
@storageRestrictions(initializes: _destination)
init(initialValue) {
_destination = PresentationState(wrappedValue: initialValue)
}
get {
_$observationRegistrar.access(self, keyPath: \.destination)
return _destination.wrappedValue
}
set {
_$observationRegistrar.mutate(self, keyPath: \.destination, &_destination.wrappedValue, newValue, _$isIdentityEqual)
}
}
var $destination: ComposableArchitecture.PresentationState<Destination.State> {
get {
_$observationRegistrar.access(self, keyPath: \.destination)
return _destination.projectedValue
}
set {
_$observationRegistrar.mutate(self, keyPath: \.destination, &_destination.projectedValue, newValue, _$isIdentityEqual)
}
}
@ObservationStateIgnored private var _destination = ComposableArchitecture.PresentationState<Destination.State>(wrappedValue: nil)
}
"""#
}
}
func testAccessControl() {
assertMacro {
"""
public struct State {
@Presents public var destination: Destination.State?
}
"""
} expansion: {
#"""
public struct State {
public var destination: Destination.State? {
@storageRestrictions(initializes: _destination)
init(initialValue) {
_destination = PresentationState(wrappedValue: initialValue)
}
get {
_$observationRegistrar.access(self, keyPath: \.destination)
return _destination.wrappedValue
}
set {
_$observationRegistrar.mutate(self, keyPath: \.destination, &_destination.wrappedValue, newValue, _$isIdentityEqual)
}
}
public var $destination: ComposableArchitecture.PresentationState<Destination.State> {
get {
_$observationRegistrar.access(self, keyPath: \.destination)
return _destination.projectedValue
}
set {
_$observationRegistrar.mutate(self, keyPath: \.destination, &_destination.projectedValue, newValue, _$isIdentityEqual)
}
}
@ObservationStateIgnored private var _destination = ComposableArchitecture.PresentationState<Destination.State>(wrappedValue: nil)
}
"""#
}
assertMacro {
"""
package struct State {
@Presents package var destination: Destination.State?
}
"""
} expansion: {
#"""
package struct State {
package var destination: Destination.State? {
@storageRestrictions(initializes: _destination)
init(initialValue) {
_destination = PresentationState(wrappedValue: initialValue)
}
get {
_$observationRegistrar.access(self, keyPath: \.destination)
return _destination.wrappedValue
}
set {
_$observationRegistrar.mutate(self, keyPath: \.destination, &_destination.wrappedValue, newValue, _$isIdentityEqual)
}
}
package var $destination: ComposableArchitecture.PresentationState<Destination.State> {
get {
_$observationRegistrar.access(self, keyPath: \.destination)
return _destination.projectedValue
}
set {
_$observationRegistrar.mutate(self, keyPath: \.destination, &_destination.projectedValue, newValue, _$isIdentityEqual)
}
}
@ObservationStateIgnored private var _destination = ComposableArchitecture.PresentationState<Destination.State>(wrappedValue: nil)
}
"""#
}
}
func testObservableStateDiagnostic() {
assertMacro([
ObservableStateMacro.self,
ObservationStateIgnoredMacro.self,
ObservationStateTrackedMacro.self,
PresentsMacro.self,
]) {
"""
@ObservableState
struct State: Equatable {
@PresentationState var destination: Destination.State?
}
"""
} diagnostics: {
"""
@ObservableState
struct State: Equatable {
@PresentationState var destination: Destination.State?
┬─────────────────
╰─ 🛑 '@PresentationState' cannot be used in '@ObservableState'
✏️ Use '@Presents' instead
}
"""
} fixes: {
"""
@ObservableState
struct State: Equatable {
@Presents var destination: Destination.State?
}
"""
} expansion: {
#"""
struct State: Equatable {
var destination: Destination.State? {
@storageRestrictions(initializes: _destination)
init(initialValue) {
_destination = PresentationState(wrappedValue: initialValue)
}
get {
_$observationRegistrar.access(self, keyPath: \.destination)
return _destination.wrappedValue
}
set {
_$observationRegistrar.mutate(self, keyPath: \.destination, &_destination.wrappedValue, newValue, _$isIdentityEqual)
}
}
var $destination: ComposableArchitecture.PresentationState<Destination.State> {
get {
_$observationRegistrar.access(self, keyPath: \.destination)
return _destination.projectedValue
}
set {
_$observationRegistrar.mutate(self, keyPath: \.destination, &_destination.projectedValue, newValue, _$isIdentityEqual)
}
}
private var _destination = ComposableArchitecture.PresentationState<Destination.State>(wrappedValue: nil)
var _$observationRegistrar = ComposableArchitecture.ObservationStateRegistrar()
public var _$id: ComposableArchitecture.ObservableStateID {
_$observationRegistrar.id
}
public mutating func _$willModify() {
_$observationRegistrar._$willModify()
}
private nonisolated func shouldNotifyObservers<__macro_local_6MemberfMu_>(_ lhs: __macro_local_6MemberfMu_, _ rhs: __macro_local_6MemberfMu_) -> Bool {
true
}
private nonisolated func shouldNotifyObservers<__macro_local_6MemberfMu0_: Equatable>(_ lhs: __macro_local_6MemberfMu0_, _ rhs: __macro_local_6MemberfMu0_) -> Bool {
lhs != rhs
}
private nonisolated func shouldNotifyObservers<__macro_local_6MemberfMu1_: AnyObject>(_ lhs: __macro_local_6MemberfMu1_, _ rhs: __macro_local_6MemberfMu1_) -> Bool {
lhs !== rhs
}
private nonisolated func shouldNotifyObservers<__macro_local_6MemberfMu2_: Equatable & AnyObject>(_ lhs: __macro_local_6MemberfMu2_, _ rhs: __macro_local_6MemberfMu2_) -> Bool {
lhs != rhs
}
}
"""#
}
}
}
#endif