mirror of
https://github.com/pointfreeco/swift-composable-architecture.git
synced 2025-12-20 09:11:33 +01:00
471 lines
12 KiB
Swift
471 lines
12 KiB
Swift
#if canImport(ComposableArchitectureMacros)
|
|
import ComposableArchitectureMacros
|
|
import MacroTesting
|
|
import XCTest
|
|
|
|
final class ViewActionMacroTests: XCTestCase {
|
|
override func invokeTest() {
|
|
withMacroTesting(
|
|
// isRecording: true,
|
|
macros: [ViewActionMacro.self]
|
|
) {
|
|
super.invokeTest()
|
|
}
|
|
}
|
|
|
|
func testLetStore() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
let store: StoreOf<Feature>
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
struct FeatureView: View {
|
|
let store: StoreOf<Feature>
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testStateStore() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
@State var store: StoreOf<Feature>
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
struct FeatureView: View {
|
|
@State var store: StoreOf<Feature>
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testStateStore_WithDefault() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
@State var store = Store(initialState: Feature.State()) {
|
|
Feature()
|
|
}
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
struct FeatureView: View {
|
|
@State var store = Store(initialState: Feature.State()) {
|
|
Feature()
|
|
}
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testBindableStore() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
@Bindable var store: StoreOf<Feature>
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
struct FeatureView: View {
|
|
@Bindable var store: StoreOf<Feature>
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testNoStore() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} diagnostics: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
╰─ 🛑 '@ViewAction' requires 'FeatureView' to have a 'store' property of type 'Store'.
|
|
✏️ Add 'store'
|
|
struct FeatureView: View {
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} fixes: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
let store: StoreOf<Feature>
|
|
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
struct FeatureView: View {
|
|
let store: StoreOf<Feature>
|
|
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testNoStore_Public() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
public struct FeatureView: View {
|
|
public var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} diagnostics: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
╰─ 🛑 '@ViewAction' requires 'FeatureView' to have a 'store' property of type 'Store'.
|
|
✏️ Add 'store'
|
|
public struct FeatureView: View {
|
|
public var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} fixes: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
public struct FeatureView: View {
|
|
public let store: StoreOf<Feature>
|
|
|
|
public var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
public struct FeatureView: View {
|
|
public let store: StoreOf<Feature>
|
|
|
|
public var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testNoStore_Package() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
package struct FeatureView: View {
|
|
package var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} diagnostics: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
╰─ 🛑 '@ViewAction' requires 'FeatureView' to have a 'store' property of type 'Store'.
|
|
✏️ Add 'store'
|
|
package struct FeatureView: View {
|
|
package var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} fixes: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
package struct FeatureView: View {
|
|
package let store: StoreOf<Feature>
|
|
|
|
package var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
package struct FeatureView: View {
|
|
package let store: StoreOf<Feature>
|
|
|
|
package var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testWarning_StoreSend() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { store.send(.tap) }
|
|
}
|
|
}
|
|
"""
|
|
} diagnostics: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { store.send(.tap) }
|
|
┬───────────────
|
|
╰─ ⚠️ Do not use 'store.send' directly when using '@ViewAction'
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { store.send(.tap) }
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testWarning_SelfStoreSend() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { self.store.send(.tap) }
|
|
}
|
|
}
|
|
"""
|
|
} diagnostics: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { self.store.send(.tap) }
|
|
┬────────────────────
|
|
╰─ ⚠️ Do not use 'store.send' directly when using '@ViewAction'
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { self.store.send(.tap) }
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testWarning_StoreSend_ViewAction() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { store.send(.view(.tap)) }
|
|
}
|
|
}
|
|
"""
|
|
} diagnostics: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { store.send(.view(.tap)) }
|
|
┬──────────────────────
|
|
╰─ ⚠️ Do not use 'store.send' directly when using '@ViewAction'
|
|
✏️ Call 'send' directly with a view action
|
|
}
|
|
}
|
|
"""
|
|
} fixes: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { send(.tap) }
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { send(.tap) }
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testWarning_SelfStoreSend_ViewAction() {
|
|
assertMacro {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { self.store.send(.view(.tap)) }
|
|
}
|
|
}
|
|
"""
|
|
} diagnostics: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { self.store.send(.view(.tap)) }
|
|
┬───────────────────────────
|
|
╰─ ⚠️ Do not use 'store.send' directly when using '@ViewAction'
|
|
✏️ Call 'send' directly with a view action
|
|
}
|
|
}
|
|
"""
|
|
} fixes: {
|
|
"""
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { self.send(.tap) }
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
struct FeatureView: View {
|
|
var store: StoreOf<Feature>
|
|
var body: some View {
|
|
Button("Tap") { self.send(.tap) }
|
|
}
|
|
}
|
|
|
|
extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
func testAvailability() {
|
|
assertMacro {
|
|
"""
|
|
@available(iOS 17, macOS 14, tvOS 17, visionOS 1, watchOS 10, *)
|
|
@ViewAction(for: Feature.self)
|
|
struct FeatureView: View {
|
|
@State var store: StoreOf<Feature>
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
"""
|
|
} expansion: {
|
|
"""
|
|
@available(iOS 17, macOS 14, tvOS 17, visionOS 1, watchOS 10, *)
|
|
struct FeatureView: View {
|
|
@State var store: StoreOf<Feature>
|
|
var body: some View {
|
|
EmptyView()
|
|
}
|
|
}
|
|
|
|
@available(iOS 17, macOS 14, tvOS 17, visionOS 1, watchOS 10, *) extension FeatureView: ComposableArchitecture.ViewActionSending {
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
}
|
|
#endif
|