diff --git a/Examples/CaseStudies/Internal/CaseStudy.swift b/Examples/CaseStudies/Internal/CaseStudy.swift index 3759a7ca6..f913c2071 100644 --- a/Examples/CaseStudies/Internal/CaseStudy.swift +++ b/Examples/CaseStudies/Internal/CaseStudy.swift @@ -1,7 +1,6 @@ import SwiftUI import UIKitNavigation -@MainActor protocol CaseStudy { var readMe: String { get } var caseStudyTitle: String { get } @@ -17,7 +16,6 @@ extension CaseStudy { } @resultBuilder -@MainActor enum CaseStudyViewBuilder { @ViewBuilder static func buildBlock() -> some View {} diff --git a/Examples/CaseStudies/ObservableModelDemo.swift b/Examples/CaseStudies/ObservableModelDemo.swift index 1735fbc88..108e562a2 100644 --- a/Examples/CaseStudies/ObservableModelDemo.swift +++ b/Examples/CaseStudies/ObservableModelDemo.swift @@ -43,7 +43,6 @@ struct ObservableModelDemo: SwiftUICaseStudy { } @Observable -@MainActor private class Model { @ObservationIgnored @FetchAll(Fact.order { $0.id.desc() }, animation: .default) diff --git a/Examples/Examples.xcodeproj/project.pbxproj b/Examples/Examples.xcodeproj/project.pbxproj index f11a0dede..7e7ad2def 100644 --- a/Examples/Examples.xcodeproj/project.pbxproj +++ b/Examples/Examples.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + CA0923FC3037ED040053D2D7 /* DebugSnapshots in Frameworks */ = {isa = PBXBuildFile; productRef = CA0923FB3037ED040053D2D7 /* DebugSnapshots */; }; + CA0923FE3037ED040053D2D7 /* DebugSnapshots in Frameworks */ = {isa = PBXBuildFile; productRef = CA0923FD3037ED040053D2D7 /* DebugSnapshots */; }; CA14DBC92DA884C400E36852 /* CasePaths in Frameworks */ = {isa = PBXBuildFile; productRef = CA14DBC82DA884C400E36852 /* CasePaths */; }; CA2908C92D4AF70E003F165F /* UIKitNavigation in Frameworks */ = {isa = PBXBuildFile; productRef = CA2908C82D4AF70E003F165F /* UIKitNavigation */; }; CA2BDE2A2E71C469000974D3 /* SQLiteData in Frameworks */ = {isa = PBXBuildFile; productRef = CA2BDE292E71C469000974D3 /* SQLiteData */; }; @@ -163,59 +165,77 @@ /* Begin PBXFrameworksBuildPhase section */ CA2BDD9A2E71C30B000974D3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; files = ( CA2BDE2A2E71C469000974D3 /* SQLiteData in Frameworks */, ); + runOnlyForDeploymentPostprocessing = 0; }; CA5E46932DEBFE410069E0F8 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; files = ( CA5E47092DECEFC80069E0F8 /* SnapshotTestingCustomDump in Frameworks */, CA5E47072DECEF0F0069E0F8 /* InlineSnapshotTesting in Frameworks */, CA5E470B2DECF0280069E0F8 /* DependenciesTestSupport in Frameworks */, ); + runOnlyForDeploymentPostprocessing = 0; }; CAD0017A2D874E6F00FA977A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; files = ( CAD001872D874F1F00FA977A /* DependenciesTestSupport in Frameworks */, ); + runOnlyForDeploymentPostprocessing = 0; }; CAF836952D4735620047AEB5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; files = ( DCB8AD4E30363F2100ACF09E /* SQLiteData in Frameworks */, CA2908C92D4AF70E003F165F /* UIKitNavigation in Frameworks */, ); + runOnlyForDeploymentPostprocessing = 0; }; CAF836A52D4735640047AEB5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CAF836D52D4735AB0047AEB5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; files = ( + CA0923FC3037ED040053D2D7 /* DebugSnapshots in Frameworks */, DCB8AD5030363F2600ACF09E /* SQLiteData in Frameworks */, CA14DBC92DA884C400E36852 /* CasePaths in Frameworks */, CA5E46912DEBB8570069E0F8 /* SwiftUINavigation in Frameworks */, ); + runOnlyForDeploymentPostprocessing = 0; }; DC1584A330363595009DD95C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; files = ( DCB8AD4A30363D3800ACF09E /* SQLiteData in Frameworks */, DCB8AD4C30363DB100ACF09E /* UIKitNavigation in Frameworks */, ); + runOnlyForDeploymentPostprocessing = 0; }; DCBE89C92D483FB90071F499 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; files = ( DCF267392D48437300B680BE /* SwiftUINavigation in Frameworks */, DC5FA7482D4C63D60082743E /* DependenciesMacros in Frameworks */, DCB8AD5230363F2A00ACF09E /* SQLiteData in Frameworks */, DCBE8A142D4842BF0071F499 /* CasePaths in Frameworks */, + CA0923FE3037ED040053D2D7 /* DebugSnapshots in Frameworks */, ); + runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ @@ -273,6 +293,8 @@ ); buildRules = ( ); + dependencies = ( + ); fileSystemSynchronizedGroups = ( CA2BDD9E2E71C30B000974D3 /* CloudKitDemo */, ); @@ -344,6 +366,8 @@ ); buildRules = ( ); + dependencies = ( + ); fileSystemSynchronizedGroups = ( CAF8369A2D4735620047AEB5 /* CaseStudies */, ); @@ -373,6 +397,8 @@ CAF836AB2D4735640047AEB5 /* CaseStudiesTests */, ); name = CaseStudiesTests; + packageProductDependencies = ( + ); productName = ExamplesTests; productReference = CAF836A82D4735640047AEB5 /* CaseStudiesTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -387,6 +413,8 @@ ); buildRules = ( ); + dependencies = ( + ); fileSystemSynchronizedGroups = ( CAF836D92D4735AB0047AEB5 /* Reminders */, ); @@ -395,6 +423,7 @@ CA14DBC82DA884C400E36852 /* CasePaths */, CA5E46902DEBB8570069E0F8 /* SwiftUINavigation */, DCB8AD4F30363F2600ACF09E /* SQLiteData */, + CA0923FB3037ED040053D2D7 /* DebugSnapshots */, ); productName = Reminders; productReference = CAF836D82D4735AB0047AEB5 /* Reminders.app */; @@ -410,6 +439,8 @@ ); buildRules = ( ); + dependencies = ( + ); fileSystemSynchronizedGroups = ( DC1584A730363595009DD95C /* Integration */, ); @@ -432,6 +463,8 @@ ); buildRules = ( ); + dependencies = ( + ); fileSystemSynchronizedGroups = ( DCBE89CD2D483FB90071F499 /* SyncUps */, ); @@ -441,6 +474,7 @@ DCF267382D48437300B680BE /* SwiftUINavigation */, DC5FA7472D4C63D60082743E /* DependenciesMacros */, DCB8AD5130363F2A00ACF09E /* SQLiteData */, + CA0923FD3037ED040053D2D7 /* DebugSnapshots */, ); productName = SyncUps; productReference = DCBE89CC2D483FB90071F499 /* SyncUps.app */; @@ -500,6 +534,7 @@ DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */, CA5E47052DECEF0F0069E0F8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, DCB8AD4830363D3800ACF09E /* XCLocalSwiftPackageReference "../../sqlite-data" */, + CA0923FA3037ED040053D2D7 /* XCRemoteSwiftPackageReference "swift-debug-snapshots" */, ); preferredProjectObjectVersion = 77; productRefGroup = CAF836992D4735620047AEB5 /* Products */; @@ -521,86 +556,118 @@ /* Begin PBXResourcesBuildPhase section */ CA2BDD9B2E71C30B000974D3 /* Resources */ = { isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CA5E46942DEBFE410069E0F8 /* Resources */ = { isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CAD0017B2D874E6F00FA977A /* Resources */ = { isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CAF836962D4735620047AEB5 /* Resources */ = { isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CAF836A62D4735640047AEB5 /* Resources */ = { isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CAF836D62D4735AB0047AEB5 /* Resources */ = { isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; DC1584A430363595009DD95C /* Resources */ = { isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; DCBE89CA2D483FB90071F499 /* Resources */ = { isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ CA2BDD992E71C30B000974D3 /* Sources */ = { isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CA5E46922DEBFE410069E0F8 /* Sources */ = { isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CAD001792D874E6F00FA977A /* Sources */ = { isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CAF836942D4735620047AEB5 /* Sources */ = { isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CAF836A42D4735640047AEB5 /* Sources */ = { isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; CAF836D42D4735AB0047AEB5 /* Sources */ = { isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; DC1584A230363595009DD95C /* Sources */ = { isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; DCBE89C82D483FB90071F499 /* Sources */ = { isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; files = ( ); + runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ @@ -623,7 +690,7 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - CA2BDDA52E71C30D000974D3 /* Debug configuration for PBXNativeTarget "CloudKitDemo" */ = { + CA2BDDA52E71C30D000974D3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -653,7 +720,7 @@ }; name = Debug; }; - CA2BDDA62E71C30D000974D3 /* Release configuration for PBXNativeTarget "CloudKitDemo" */ = { + CA2BDDA62E71C30D000974D3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -683,7 +750,7 @@ }; name = Release; }; - CA5E469D2DEBFE420069E0F8 /* Debug configuration for PBXNativeTarget "RemindersTests" */ = { + CA5E469D2DEBFE420069E0F8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; @@ -700,7 +767,7 @@ }; name = Debug; }; - CA5E469E2DEBFE420069E0F8 /* Release configuration for PBXNativeTarget "RemindersTests" */ = { + CA5E469E2DEBFE420069E0F8 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; @@ -717,7 +784,7 @@ }; name = Release; }; - CAD001832D874E6F00FA977A /* Debug configuration for PBXNativeTarget "SyncUpTests" */ = { + CAD001832D874E6F00FA977A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; @@ -734,7 +801,7 @@ }; name = Debug; }; - CAD001842D874E6F00FA977A /* Release configuration for PBXNativeTarget "SyncUpTests" */ = { + CAD001842D874E6F00FA977A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; @@ -751,7 +818,7 @@ }; name = Release; }; - CAF836BA2D4735640047AEB5 /* Debug configuration for PBXProject "Examples" */ = { + CAF836BA2D4735640047AEB5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -818,7 +885,7 @@ }; name = Debug; }; - CAF836BB2D4735640047AEB5 /* Release configuration for PBXProject "Examples" */ = { + CAF836BB2D4735640047AEB5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -878,7 +945,7 @@ }; name = Release; }; - CAF836BD2D4735640047AEB5 /* Debug configuration for PBXNativeTarget "CaseStudies" */ = { + CAF836BD2D4735640047AEB5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -906,7 +973,7 @@ }; name = Debug; }; - CAF836BE2D4735640047AEB5 /* Release configuration for PBXNativeTarget "CaseStudies" */ = { + CAF836BE2D4735640047AEB5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -934,7 +1001,7 @@ }; name = Release; }; - CAF836C02D4735640047AEB5 /* Debug configuration for PBXNativeTarget "CaseStudiesTests" */ = { + CAF836C02D4735640047AEB5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; @@ -950,7 +1017,7 @@ }; name = Debug; }; - CAF836C12D4735640047AEB5 /* Release configuration for PBXNativeTarget "CaseStudiesTests" */ = { + CAF836C12D4735640047AEB5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; @@ -966,7 +1033,7 @@ }; name = Release; }; - CAF836FA2D4735AD0047AEB5 /* Debug configuration for PBXNativeTarget "Reminders" */ = { + CAF836FA2D4735AD0047AEB5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -996,7 +1063,7 @@ }; name = Debug; }; - CAF836FB2D4735AD0047AEB5 /* Release configuration for PBXNativeTarget "Reminders" */ = { + CAF836FB2D4735AD0047AEB5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1026,7 +1093,7 @@ }; name = Release; }; - DC1584AF30363596009DD95C /* Debug configuration for PBXNativeTarget "Integration" */ = { + DC1584AF30363596009DD95C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1057,7 +1124,7 @@ }; name = Debug; }; - DC1584B030363596009DD95C /* Release configuration for PBXNativeTarget "Integration" */ = { + DC1584B030363596009DD95C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1088,7 +1155,7 @@ }; name = Release; }; - DCBE89ED2D483FBA0071F499 /* Debug configuration for PBXNativeTarget "SyncUps" */ = { + DCBE89ED2D483FBA0071F499 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1119,7 +1186,7 @@ }; name = Debug; }; - DCBE89EE2D483FBA0071F499 /* Release configuration for PBXNativeTarget "SyncUps" */ = { + DCBE89EE2D483FBA0071F499 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1156,73 +1223,82 @@ CA2BDDA72E71C30D000974D3 /* Build configuration list for PBXNativeTarget "CloudKitDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( - CA2BDDA52E71C30D000974D3 /* Debug configuration for PBXNativeTarget "CloudKitDemo" */, - CA2BDDA62E71C30D000974D3 /* Release configuration for PBXNativeTarget "CloudKitDemo" */, + CA2BDDA52E71C30D000974D3 /* Debug */, + CA2BDDA62E71C30D000974D3 /* Release */, ); + defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; CA5E469C2DEBFE420069E0F8 /* Build configuration list for PBXNativeTarget "RemindersTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - CA5E469D2DEBFE420069E0F8 /* Debug configuration for PBXNativeTarget "RemindersTests" */, - CA5E469E2DEBFE420069E0F8 /* Release configuration for PBXNativeTarget "RemindersTests" */, + CA5E469D2DEBFE420069E0F8 /* Debug */, + CA5E469E2DEBFE420069E0F8 /* Release */, ); + defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; CAD001852D874E6F00FA977A /* Build configuration list for PBXNativeTarget "SyncUpTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - CAD001832D874E6F00FA977A /* Debug configuration for PBXNativeTarget "SyncUpTests" */, - CAD001842D874E6F00FA977A /* Release configuration for PBXNativeTarget "SyncUpTests" */, + CAD001832D874E6F00FA977A /* Debug */, + CAD001842D874E6F00FA977A /* Release */, ); + defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; CAF836932D4735620047AEB5 /* Build configuration list for PBXProject "Examples" */ = { isa = XCConfigurationList; buildConfigurations = ( - CAF836BA2D4735640047AEB5 /* Debug configuration for PBXProject "Examples" */, - CAF836BB2D4735640047AEB5 /* Release configuration for PBXProject "Examples" */, + CAF836BA2D4735640047AEB5 /* Debug */, + CAF836BB2D4735640047AEB5 /* Release */, ); + defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; CAF836BC2D4735640047AEB5 /* Build configuration list for PBXNativeTarget "CaseStudies" */ = { isa = XCConfigurationList; buildConfigurations = ( - CAF836BD2D4735640047AEB5 /* Debug configuration for PBXNativeTarget "CaseStudies" */, - CAF836BE2D4735640047AEB5 /* Release configuration for PBXNativeTarget "CaseStudies" */, + CAF836BD2D4735640047AEB5 /* Debug */, + CAF836BE2D4735640047AEB5 /* Release */, ); + defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; CAF836BF2D4735640047AEB5 /* Build configuration list for PBXNativeTarget "CaseStudiesTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - CAF836C02D4735640047AEB5 /* Debug configuration for PBXNativeTarget "CaseStudiesTests" */, - CAF836C12D4735640047AEB5 /* Release configuration for PBXNativeTarget "CaseStudiesTests" */, + CAF836C02D4735640047AEB5 /* Debug */, + CAF836C12D4735640047AEB5 /* Release */, ); + defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; CAF836F92D4735AD0047AEB5 /* Build configuration list for PBXNativeTarget "Reminders" */ = { isa = XCConfigurationList; buildConfigurations = ( - CAF836FA2D4735AD0047AEB5 /* Debug configuration for PBXNativeTarget "Reminders" */, - CAF836FB2D4735AD0047AEB5 /* Release configuration for PBXNativeTarget "Reminders" */, + CAF836FA2D4735AD0047AEB5 /* Debug */, + CAF836FB2D4735AD0047AEB5 /* Release */, ); + defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DC1584AE30363596009DD95C /* Build configuration list for PBXNativeTarget "Integration" */ = { isa = XCConfigurationList; buildConfigurations = ( - DC1584AF30363596009DD95C /* Debug configuration for PBXNativeTarget "Integration" */, - DC1584B030363596009DD95C /* Release configuration for PBXNativeTarget "Integration" */, + DC1584AF30363596009DD95C /* Debug */, + DC1584B030363596009DD95C /* Release */, ); + defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DCBE89F32D483FBA0071F499 /* Build configuration list for PBXNativeTarget "SyncUps" */ = { isa = XCConfigurationList; buildConfigurations = ( - DCBE89ED2D483FBA0071F499 /* Debug configuration for PBXNativeTarget "SyncUps" */, - DCBE89EE2D483FBA0071F499 /* Release configuration for PBXNativeTarget "SyncUps" */, + DCBE89ED2D483FBA0071F499 /* Debug */, + DCBE89EE2D483FBA0071F499 /* Release */, ); + defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ @@ -1232,15 +1308,21 @@ isa = XCLocalSwiftPackageReference; relativePath = "../../sqlite-data"; traits = ( - CasePaths, - ColumnCoding, - LazyInitializableByDefault, - StrictDecoding, ); }; /* End XCLocalSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */ + CA0923FA3037ED040053D2D7 /* XCRemoteSwiftPackageReference "swift-debug-snapshots" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/pointfreeco/swift-debug-snapshots.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.1.0; + }; + traits = ( + ); + }; CA5E47052DECEF0F0069E0F8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing.git"; @@ -1276,6 +1358,16 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + CA0923FB3037ED040053D2D7 /* DebugSnapshots */ = { + isa = XCSwiftPackageProductDependency; + package = CA0923FA3037ED040053D2D7 /* XCRemoteSwiftPackageReference "swift-debug-snapshots" */; + productName = DebugSnapshots; + }; + CA0923FD3037ED040053D2D7 /* DebugSnapshots */ = { + isa = XCSwiftPackageProductDependency; + package = CA0923FA3037ED040053D2D7 /* XCRemoteSwiftPackageReference "swift-debug-snapshots" */; + productName = DebugSnapshots; + }; CA14DBC82DA884C400E36852 /* CasePaths */ = { isa = XCSwiftPackageProductDependency; package = DCBE8A122D4842BF0071F499 /* XCRemoteSwiftPackageReference "swift-case-paths" */; diff --git a/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 000000000..387fb68e5 --- /dev/null +++ b/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,159 @@ +{ + "originHash" : "ad41d862cbf4ae7f82f17f353075ecb723d246b512a0877f555e27ec8185459a", + "pins" : [ + { + "identity" : "combine-schedulers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/combine-schedulers", + "state" : { + "revision" : "114354e8c1667a2edc4993700fb9fa4f90157b56", + "version" : "1.2.2" + } + }, + { + "identity" : "grdb.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/groue/GRDB.swift", + "state" : { + "revision" : "b83108d10f42680d78f23fe4d4d80fc88dab3212", + "version" : "7.11.1" + } + }, + { + "identity" : "swift-case-paths", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-case-paths", + "state" : { + "revision" : "cb4cba6a8a46a86db0d37dbe09935ead6b24c91a", + "version" : "1.10.0" + } + }, + { + "identity" : "swift-clocks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-clocks", + "state" : { + "revision" : "82440fa0a8b1c381a6d1e8e0fc7bbba53ec63204", + "version" : "1.1.1" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections", + "state" : { + "revision" : "98ef3c98609a1e31b7e157b5b619579001a789d6", + "version" : "1.7.1" + } + }, + { + "identity" : "swift-concurrency-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-concurrency-extras", + "state" : { + "revision" : "5fa253428866f2360c3754e88537f700ed2656b5", + "version" : "1.4.1" + } + }, + { + "identity" : "swift-custom-dump", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-custom-dump", + "state" : { + "revision" : "4fb9e7cbb4b8f5a7354005db39447f570d6b3e19", + "version" : "1.7.3" + } + }, + { + "identity" : "swift-debug-snapshots", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-debug-snapshots.git", + "state" : { + "revision" : "4e06b3615bd5e193525b331c218934dd42d30b2e", + "version" : "0.5.2" + } + }, + { + "identity" : "swift-dependencies", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-dependencies", + "state" : { + "revision" : "b476cc5761057d8d857de063fe7ac8daecf5c06b", + "version" : "1.17.1" + } + }, + { + "identity" : "swift-identified-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-identified-collections", + "state" : { + "revision" : "322d9ffeeba85c9f7c4984b39422ec7cc3c56597", + "version" : "1.1.1" + } + }, + { + "identity" : "swift-issue-reporting", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-issue-reporting", + "state" : { + "revision" : "75b000cea2ca6d7527a57e1b9cc0bdf21a9abe9f", + "version" : "2.1.1" + } + }, + { + "identity" : "swift-navigation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-navigation", + "state" : { + "revision" : "7e95e5e9ff0a64f6ad8bca59083f8d6ba381b6ff", + "version" : "2.11.2" + } + }, + { + "identity" : "swift-perception", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-perception", + "state" : { + "revision" : "597afd46249f4a71885b95d26b26cc5b893daf32", + "version" : "2.0.12" + } + }, + { + "identity" : "swift-sharing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-sharing", + "state" : { + "revision" : "3552faf8a6c18ce896ec5a72bd8c34755f0f03e0", + "version" : "2.10.1" + } + }, + { + "identity" : "swift-snapshot-testing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-snapshot-testing.git", + "state" : { + "revision" : "28e5de025e3fd98991791bfbf83023ab3708da03", + "version" : "1.19.6" + } + }, + { + "identity" : "swift-structured-queries", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-structured-queries", + "state" : { + "revision" : "72d536d5f0319097612bea961e356f4223efd926", + "version" : "0.39.2" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swiftlang/swift-syntax", + "state" : { + "revision" : "050f1a346fbbac0ca2cfb15a95274f7bd1cf0ccf", + "version" : "604.0.0" + } + } + ], + "version" : 3 +} diff --git a/Examples/Examples.xcodeproj/xcshareddata/xcschemes/Integration.xcscheme b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/Integration.xcscheme index 45608be57..02cde499a 100644 --- a/Examples/Examples.xcodeproj/xcshareddata/xcschemes/Integration.xcscheme +++ b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/Integration.xcscheme @@ -17,6 +17,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "DC1584A530363595009DD95C" BuildableName = "Integration.app" + BlueprintName = "Integration" ReferencedContainer = "container:Examples.xcodeproj"> @@ -46,6 +47,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "DC1584A530363595009DD95C" BuildableName = "Integration.app" + BlueprintName = "Integration" ReferencedContainer = "container:Examples.xcodeproj"> @@ -62,6 +64,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "DC1584A530363595009DD95C" BuildableName = "Integration.app" + BlueprintName = "Integration" ReferencedContainer = "container:Examples.xcodeproj"> diff --git a/Examples/Reminders/Helpers.swift b/Examples/Reminders/Helpers.swift index aa889bf87..6e3774369 100644 --- a/Examples/Reminders/Helpers.swift +++ b/Examples/Reminders/Helpers.swift @@ -23,10 +23,10 @@ extension Color { public var hexValue: Int64? { guard let components = UIColor(queryOutput).cgColor.components else { return nil } - let r = Int64(components[0] * 0xFF) << 24 - let g = Int64(components[1] * 0xFF) << 16 - let b = Int64(components[2] * 0xFF) << 8 - let a = Int64((components.indices.contains(3) ? components[3] : 1) * 0xFF) + let r = Int64((components[0] * 0xFF).rounded()) << 24 + let g = Int64((components[1] * 0xFF).rounded()) << 16 + let b = Int64((components[2] * 0xFF).rounded()) << 8 + let a = Int64(((components.indices.contains(3) ? components[3] : 1) * 0xFF).rounded()) return r | g | b | a } diff --git a/Examples/Reminders/RemindersDetail.swift b/Examples/Reminders/RemindersDetail.swift index a9cd88407..1e1d978af 100644 --- a/Examples/Reminders/RemindersDetail.swift +++ b/Examples/Reminders/RemindersDetail.swift @@ -1,11 +1,12 @@ import CasePaths import CloudKit +import DebugSnapshots import SQLiteData import Sharing import SwiftUI import SwiftUINavigation -@MainActor +@DebugSnapshot @Observable class RemindersDetailModel: HashableObject { @ObservationIgnored @FetchAll var reminderRows: [Row] @@ -165,11 +166,11 @@ class RemindersDetailModel: HashableObject { @Selection struct Row: Identifiable { var id: Reminder.ID { reminder.id } - let reminder: Reminder - let remindersList: RemindersList - let isPastDue: Bool - let notes: String - let tags: String + var reminder: Reminder + var remindersList: RemindersList + var isPastDue: Bool + var notes: String + var tags: String } } diff --git a/Examples/Reminders/RemindersLists.swift b/Examples/Reminders/RemindersLists.swift index 11080ec35..68dcd641d 100644 --- a/Examples/Reminders/RemindersLists.swift +++ b/Examples/Reminders/RemindersLists.swift @@ -1,10 +1,11 @@ import CloudKit +import DebugSnapshots import SQLiteData import SwiftUI import SwiftUINavigation import TipKit -@MainActor +@DebugSnapshot @Observable class RemindersListsModel { @ObservationIgnored @@ -49,8 +50,8 @@ class RemindersListsModel { ) var stats = Stats() - var destination: Destination? - var searchRemindersModel = SearchRemindersModel() + @DebugSnapshotConvertible var destination: Destination? + @DebugSnapshotConvertible var searchRemindersModel = SearchRemindersModel() var seedDatabaseTip: SeedDatabaseTip? @ObservationIgnored @@ -131,8 +132,8 @@ class RemindersListsModel { let (first, rest) = (ids.first!, ids.dropFirst()) $0.position = rest - .reduce(Case($0.id).when(first.element, then: first.offset)) { cases, id in - cases.when(id.element, then: id.offset) + .reduce(Case($0.id).when(first.element, then: first.offset + 1)) { cases, id in + cases.when(id.element, then: id.offset + 1) } .else($0.position) } @@ -150,7 +151,9 @@ class RemindersListsModel { #endif @CasePathable + @DebugSnapshot enum Destination { + @DebugSnapshotConvertible case detail(RemindersDetailModel) case reminderForm(Reminder.Draft, remindersList: RemindersList) case remindersListForm(RemindersList.Draft) diff --git a/Examples/Reminders/Schema.swift b/Examples/Reminders/Schema.swift index 54dc8f4fc..e63f667a9 100644 --- a/Examples/Reminders/Schema.swift +++ b/Examples/Reminders/Schema.swift @@ -14,12 +14,18 @@ nonisolated struct RemindersList: Hashable, Identifiable { var position = 0 var title = "" - static var defaultColor: Color { Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255) } + static var defaultColor: Color { .personal } static var defaultTitle: String { "Personal" } } extension RemindersList.Draft: Identifiable {} +nonisolated extension Color { + static let personal = Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255) + static let family = Color(red: 0xed / 255, green: 0x89 / 255, blue: 0x35 / 255) + static let business = Color(red: 0xb2 / 255, green: 0x5d / 255, blue: 0xd3 / 255) +} + @Table nonisolated struct RemindersListAsset: Hashable, Identifiable { @Column(primaryKey: true) @@ -424,17 +430,17 @@ nonisolated private let logger = Logger(subsystem: "Reminders", category: "Datab try db.seed { RemindersList( id: remindersListIDs[0], - color: Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255), + color: .personal, title: "Personal" ) RemindersList( id: remindersListIDs[1], - color: Color(red: 0xed / 255, green: 0x89 / 255, blue: 0x35 / 255), + color: .family, title: "Family" ) RemindersList( id: remindersListIDs[2], - color: Color(red: 0xb2 / 255, green: 0x5d / 255, blue: 0xd3 / 255), + color: .business, title: "Business" ) Reminder( diff --git a/Examples/Reminders/SearchReminders.swift b/Examples/Reminders/SearchReminders.swift index 9c33dfcae..586019c6f 100644 --- a/Examples/Reminders/SearchReminders.swift +++ b/Examples/Reminders/SearchReminders.swift @@ -1,8 +1,9 @@ +import DebugSnapshots import IssueReporting import SQLiteData import SwiftUI -@MainActor +@DebugSnapshot @Observable class SearchRemindersModel { var showCompletedInSearchResults = false { @@ -40,6 +41,7 @@ class SearchRemindersModel { !searchText.isEmpty || !searchTokens.isEmpty } + @DebugSnapshotIgnored var searchTask: Task? { willSet { searchTask?.cancel() @@ -115,12 +117,12 @@ class SearchRemindersModel { @Selection struct Row: Identifiable { var id: Reminder.ID { reminder.id } - let isPastDue: Bool - let notes: String - let reminder: Reminders.Reminder - let remindersList: RemindersList - let tags: String - let title: String + var isPastDue: Bool + var notes: String + var reminder: Reminders.Reminder + var remindersList: RemindersList + var tags: String + var title: String } struct SearchRequest: FetchKeyRequest { diff --git a/Examples/RemindersTests/Internal.swift b/Examples/RemindersTests/Internal.swift index 6d763a8f9..93030018e 100644 --- a/Examples/RemindersTests/Internal.swift +++ b/Examples/RemindersTests/Internal.swift @@ -11,9 +11,9 @@ import Testing .dependency(\.date.now, Date(timeIntervalSince1970: 1_234_567_890)), .dependency(\.uuid, .incrementing), .dependencies { - try $0.bootstrapDatabase() + try await $0.bootstrapDatabase() try await $0.defaultSyncEngine.start() - try $0.defaultDatabase.seedSampleData() + try await $0.defaultDatabase.seedTestData() try await $0.defaultSyncEngine.sendChanges() }, .snapshots(record: .missing) diff --git a/Examples/RemindersTests/RemindersDetailsTests.swift b/Examples/RemindersTests/RemindersDetailsTests.swift index 18ea8fb6c..cf96ea812 100644 --- a/Examples/RemindersTests/RemindersDetailsTests.swift +++ b/Examples/RemindersTests/RemindersDetailsTests.swift @@ -1,94 +1,70 @@ +import DebugSnapshots import Dependencies import DependenciesTestSupport +import Foundation import InlineSnapshotTesting +import SQLiteData import SnapshotTestingCustomDump import Testing @testable import Reminders extension BaseTestSuite { - @MainActor struct RemindersDetailsTests { @Dependency(\.defaultDatabase) var database @Test func basics() async throws { let remindersList = try await database.read { try RemindersList.fetchOne($0)! } let model = RemindersDetailModel(detailType: .remindersList(remindersList)) - try await model.$reminderRows.load() - assertInlineSnapshot(of: model.reminderRows, as: .customDump) { - #""" - [ - [0]: RemindersDetailModel.Row( + try await expect(model) { + try await model.$reminderRows.load() + } changes: { + $0.reminderRows = [ + RemindersDetailModel.Row( reminder: Reminder( - id: UUID(00000000-0000-0000-0000-000000000004), - dueDate: Date(2009-02-11T23:31:30.000Z), + id: UUID(4), + dueDate: Date(timeIntervalSince1970: 1_234_395_090), isFlagged: true, - notes: "", position: 2, - priority: nil, - remindersListID: UUID(00000000-0000-0000-0000-000000000000), - status: .incomplete, + remindersListID: UUID(0), title: "Haircut" ), - remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000000), - color: 1218047999, - position: 1, - title: "Personal" - ), + remindersList: remindersList, isPastDue: true, notes: "", tags: "#someday #optional" ), - [1]: RemindersDetailModel.Row( + RemindersDetailModel.Row( reminder: Reminder( - id: UUID(00000000-0000-0000-0000-000000000005), - dueDate: Date(2009-02-13T23:31:30.000Z), - isFlagged: false, + id: UUID(5), + dueDate: Date(timeIntervalSince1970: 1_234_567_890), notes: "Ask about diet", position: 3, priority: .high, - remindersListID: UUID(00000000-0000-0000-0000-000000000000), - status: .incomplete, + remindersListID: UUID(0), title: "Doctor appointment" ), - remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000000), - color: 1218047999, - position: 1, - title: "Personal" - ), + remindersList: remindersList, isPastDue: false, notes: "Ask about diet", tags: "#adulting" ), - [2]: RemindersDetailModel.Row( + RemindersDetailModel.Row( reminder: Reminder( - id: UUID(00000000-0000-0000-0000-000000000007), - dueDate: Date(2009-02-13T23:31:30.000Z), - isFlagged: false, - notes: "", + id: UUID(7), + dueDate: Date(timeIntervalSince1970: 1_234_567_890), position: 5, - priority: nil, - remindersListID: UUID(00000000-0000-0000-0000-000000000000), - status: .incomplete, + remindersListID: UUID(0), title: "Buy concert tickets" ), - remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000000), - color: 1218047999, - position: 1, - title: "Personal" - ), + remindersList: remindersList, isPastDue: false, notes: "", tags: "#social #night" ), - [3]: RemindersDetailModel.Row( + RemindersDetailModel.Row( reminder: Reminder( - id: UUID(00000000-0000-0000-0000-000000000003), - dueDate: nil, - isFlagged: false, + id: UUID(3), notes: """ Milk Eggs @@ -97,23 +73,15 @@ extension BaseTestSuite { Spinach """, position: 1, - priority: nil, - remindersListID: UUID(00000000-0000-0000-0000-000000000000), - status: .incomplete, + remindersListID: UUID(0), title: "Groceries" ), - remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000000), - color: 1218047999, - position: 1, - title: "Personal" - ), + remindersList: remindersList, isPastDue: false, notes: "Milk Eggs Apples Oatmeal Spinach", tags: "#someday #optional #adulting" - ) + ), ] - """# } } @@ -122,44 +90,32 @@ extension BaseTestSuite { let model = RemindersDetailModel(detailType: .remindersList(remindersList)) try await model.$reminderRows.load() - #expect(model.ordering == .dueDate) - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Haircut", - [1]: "Doctor appointment", - [2]: "Buy concert tickets", - [3]: "Groceries" - ] - """ + expect(model) { + $0.ordering = .dueDate + $0.reminderRows[0].reminder.title = "Haircut" + $0.reminderRows[1].reminder.title = "Doctor appointment" + $0.reminderRows[2].reminder.title = "Buy concert tickets" + $0.reminderRows[3].reminder.title = "Groceries" } await model.orderingButtonTapped(.priority) try await model.$reminderRows.load() - #expect(model.ordering == .priority) - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Doctor appointment", - [1]: "Haircut", - [2]: "Groceries", - [3]: "Buy concert tickets" - ] - """ + expect(model) { + $0.ordering = .priority + $0.reminderRows[0].reminder.title = "Doctor appointment" + $0.reminderRows[1].reminder.title = "Haircut" + $0.reminderRows[2].reminder.title = "Groceries" + $0.reminderRows[3].reminder.title = "Buy concert tickets" } await model.orderingButtonTapped(.title) try await model.$reminderRows.load() - #expect(model.ordering == .title) - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Buy concert tickets", - [1]: "Doctor appointment", - [2]: "Groceries", - [3]: "Haircut" - ] - """ + expect(model) { + $0.ordering = .title + $0.reminderRows[0].reminder.title = "Buy concert tickets" + $0.reminderRows[1].reminder.title = "Doctor appointment" + $0.reminderRows[2].reminder.title = "Groceries" + $0.reminderRows[3].reminder.title = "Haircut" } } @@ -168,45 +124,33 @@ extension BaseTestSuite { let model = RemindersDetailModel(detailType: .remindersList(remindersList)) try await model.$reminderRows.load() - #expect(model.showCompleted == false) - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Haircut", - [1]: "Doctor appointment", - [2]: "Buy concert tickets", - [3]: "Groceries" - ] - """ + expect(model) { + $0.showCompleted = false + $0.reminderRows[0].reminder.title = "Haircut" + $0.reminderRows[1].reminder.title = "Doctor appointment" + $0.reminderRows[2].reminder.title = "Buy concert tickets" + $0.reminderRows[3].reminder.title = "Groceries" } await model.showCompletedButtonTapped() try await model.$reminderRows.load() - #expect(model.showCompleted == true) - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Haircut", - [1]: "Doctor appointment", - [2]: "Buy concert tickets", - [3]: "Groceries", - [4]: "Take a walk" - ] - """ + expect(model) { + $0.showCompleted = true + $0.reminderRows[0].reminder.title = "Haircut" + $0.reminderRows[1].reminder.title = "Doctor appointment" + $0.reminderRows[2].reminder.title = "Buy concert tickets" + $0.reminderRows[3].reminder.title = "Groceries" + $0.reminderRows[4].reminder.title = "Take a walk" } await model.showCompletedButtonTapped() try await model.$reminderRows.load() - #expect(model.showCompleted == false) - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Haircut", - [1]: "Doctor appointment", - [2]: "Buy concert tickets", - [3]: "Groceries" - ] - """ + expect(model) { + $0.showCompleted = false + $0.reminderRows[0].reminder.title = "Haircut" + $0.reminderRows[1].reminder.title = "Doctor appointment" + $0.reminderRows[2].reminder.title = "Buy concert tickets" + $0.reminderRows[3].reminder.title = "Groceries" } } @@ -215,106 +159,78 @@ extension BaseTestSuite { let model = RemindersDetailModel(detailType: .remindersList(remindersList)) try await model.$reminderRows.load() - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Haircut", - [1]: "Doctor appointment", - [2]: "Buy concert tickets", - [3]: "Groceries" - ] - """ + expect(model) { + $0.reminderRows[0].reminder.title = "Haircut" + $0.reminderRows[1].reminder.title = "Doctor appointment" + $0.reminderRows[2].reminder.title = "Buy concert tickets" + $0.reminderRows[3].reminder.title = "Groceries" } await model.move(from: [2], to: 0) try await model.$reminderRows.load() - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Buy concert tickets", - [1]: "Haircut", - [2]: "Doctor appointment", - [3]: "Groceries" - ] - """ + expect(model) { + $0.ordering = .manual + $0.reminderRows[0].reminder.title = "Buy concert tickets" + $0.reminderRows[1].reminder.title = "Haircut" + $0.reminderRows[2].reminder.title = "Doctor appointment" + $0.reminderRows[3].reminder.title = "Groceries" } - #expect(model.ordering == .manual) } @Test func all() async throws { let model = RemindersDetailModel(detailType: .all) try await model.$reminderRows.load() - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Haircut", - [1]: "Doctor appointment", - [2]: "Buy concert tickets", - [3]: "Pick up kids from school", - [4]: "Call accountant", - [5]: "Prepare for WWDC", - [6]: "Take out trash", - [7]: "Groceries" - ] - """ + expect(model) { + $0.reminderRows[0].reminder.title = "Haircut" + $0.reminderRows[1].reminder.title = "Doctor appointment" + $0.reminderRows[2].reminder.title = "Buy concert tickets" + $0.reminderRows[3].reminder.title = "Pick up kids from school" + $0.reminderRows[4].reminder.title = "Call accountant" + $0.reminderRows[5].reminder.title = "Prepare for WWDC" + $0.reminderRows[6].reminder.title = "Take out trash" + $0.reminderRows[7].reminder.title = "Groceries" } } @Test func completed() async throws { let model = RemindersDetailModel(detailType: .completed) try await model.$reminderRows.load() - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Take a walk", - [1]: "Get laundry", - [2]: "Send weekly emails" - ] - """ + expect(model) { + $0.reminderRows[0].reminder.title = "Take a walk" + $0.reminderRows[1].reminder.title = "Get laundry" + $0.reminderRows[2].reminder.title = "Send weekly emails" } } @Test func flagged() async throws { let model = RemindersDetailModel(detailType: .flagged) try await model.$reminderRows.load() - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Haircut", - [1]: "Pick up kids from school" - ] - """ + expect(model) { + $0.reminderRows[0].reminder.title = "Haircut" + $0.reminderRows[1].reminder.title = "Pick up kids from school" } } @Test func scheduled() async throws { let model = RemindersDetailModel(detailType: .scheduled) try await model.$reminderRows.load() - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Haircut", - [1]: "Doctor appointment", - [2]: "Buy concert tickets", - [3]: "Pick up kids from school", - [4]: "Call accountant", - [5]: "Prepare for WWDC", - [6]: "Take out trash" - ] - """ + expect(model) { + $0.reminderRows[0].reminder.title = "Haircut" + $0.reminderRows[1].reminder.title = "Doctor appointment" + $0.reminderRows[2].reminder.title = "Buy concert tickets" + $0.reminderRows[3].reminder.title = "Pick up kids from school" + $0.reminderRows[4].reminder.title = "Call accountant" + $0.reminderRows[5].reminder.title = "Prepare for WWDC" + $0.reminderRows[6].reminder.title = "Take out trash" } } @Test func today() async throws { let model = RemindersDetailModel(detailType: .today) try await model.$reminderRows.load() - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Doctor appointment", - [1]: "Buy concert tickets" - ] - """ + expect(model) { + $0.reminderRows[0].reminder.title = "Doctor appointment" + $0.reminderRows[1].reminder.title = "Buy concert tickets" } } @@ -322,13 +238,9 @@ extension BaseTestSuite { let tag = try await database.read { try Tag.find($0, key: "someday") } let model = RemindersDetailModel(detailType: .tags([tag])) try await model.$reminderRows.load() - assertInlineSnapshot(of: model.reminderRows.map(\.reminder.title), as: .customDump) { - """ - [ - [0]: "Haircut", - [1]: "Groceries" - ] - """ + expect(model) { + $0.reminderRows[0].reminder.title = "Haircut" + $0.reminderRows[1].reminder.title = "Groceries" } } } diff --git a/Examples/RemindersTests/RemindersListsTests.swift b/Examples/RemindersTests/RemindersListsTests.swift index 97d01089c..0e90d9032 100644 --- a/Examples/RemindersTests/RemindersListsTests.swift +++ b/Examples/RemindersTests/RemindersListsTests.swift @@ -1,108 +1,96 @@ +import CloudKit +import DebugSnapshots import Dependencies import DependenciesTestSupport import Foundation import InlineSnapshotTesting +import SQLiteData import SnapshotTestingCustomDump import Testing @testable import Reminders extension BaseTestSuite { - @MainActor struct RemindersListsTests { @Dependency(\.defaultDatabase) var database @Dependency(\.defaultSyncEngine) var syncEngine @Test func basics() async throws { let model = RemindersListsModel() - try await model.$remindersLists.load() - try await model.$stats.load() - try await model.$tags.load() - - assertInlineSnapshot(of: model.remindersLists, as: .customDump) { - """ - [ - [0]: RemindersListsModel.ReminderListState( + try await expect(model) { + try await model.$remindersLists.load() + try await model.$stats.load() + try await model.$tags.load() + } changes: { + $0.remindersLists = [ + RemindersListsModel.ReminderListState( remindersCount: 4, remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000000), - color: 1218047999, + id: UUID(0), + color: .personal, position: 1, title: "Personal" ), share: nil ), - [1]: RemindersListsModel.ReminderListState( + RemindersListsModel.ReminderListState( remindersCount: 2, remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000001), - color: 3985191935, + id: UUID(1), + color: .family, position: 2, title: "Family" ), share: nil ), - [2]: RemindersListsModel.ReminderListState( + RemindersListsModel.ReminderListState( remindersCount: 2, remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000002), - color: 2992493567, + id: UUID(2), + color: .business, position: 3, title: "Business" ), share: nil - ) + ), ] - """ - } - assertInlineSnapshot(of: model.stats, as: .customDump) { - """ - RemindersListsModel.Stats( + $0.stats = RemindersListsModel.Stats( allCount: 8, flaggedCount: 2, scheduledCount: 7, todayCount: 2 ) - """ - } - assertInlineSnapshot(of: model.tags, as: .customDump) { - """ - [ - [0]: Tag(title: "adulting"), - [1]: Tag(title: "car"), - [2]: Tag(title: "kids"), - [3]: Tag(title: "night"), - [4]: Tag(title: "optional"), - [5]: Tag(title: "social"), - [6]: Tag(title: "someday") + $0.tags = [ + Tag(title: "adulting"), + Tag(title: "car"), + Tag(title: "kids"), + Tag(title: "night"), + Tag(title: "optional"), + Tag(title: "social"), + Tag(title: "someday"), ] - """ } } @Test func move() async throws { let model = RemindersListsModel() - try await model.$remindersLists.load() - assertInlineSnapshot(of: model.remindersLists.map(\.remindersList.title), as: .customDump) { - """ - [ - [0]: "Personal", - [1]: "Family", - [2]: "Business" - ] - """ + + try await expect(model) { + try await model.$remindersLists.load() + } changes: { + $0.remindersLists[0].remindersList.title = "Personal" + $0.remindersLists[1].remindersList.title = "Family" + $0.remindersLists[2].remindersList.title = "Business" } - model.move(from: [2], to: 0) - try await model.$remindersLists.load() - assertInlineSnapshot(of: model.remindersLists.map(\.remindersList.title), as: .customDump) { - """ - [ - [0]: "Business", - [1]: "Personal", - [2]: "Family" - ] - """ + try await expect(model) { + model.move(from: [2], to: 0) + try await model.$remindersLists.load() + } changes: { + $0.remindersLists.move(fromOffsets: [2], toOffset: 0) + $0.remindersLists[0].remindersList.position = 1 + $0.remindersLists[1].remindersList.position = 2 + $0.remindersLists[2].remindersList.position = 3 } } @@ -114,44 +102,18 @@ extension BaseTestSuite { try RemindersList.find(UUID(0)).fetchOne(db) } ) - let _ = try await syncEngine.share(record: personalRemindersList, configure: { _ in }) + let share = try await syncEngine.share( + record: personalRemindersList, + configure: { _ in } + ) + .share - try await model.$remindersLists.load() - assertInlineSnapshot(of: model.remindersLists, as: .customDump) { - """ - [ - [0]: RemindersListsModel.ReminderListState( - remindersCount: 4, - remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000000), - color: 1218047999, - position: 1, - title: "Personal" - ), - share: CKShare() - ), - [1]: RemindersListsModel.ReminderListState( - remindersCount: 2, - remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000001), - color: 3985191935, - position: 2, - title: "Family" - ), - share: nil - ), - [2]: RemindersListsModel.ReminderListState( - remindersCount: 2, - remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000002), - color: 2992493567, - position: 3, - title: "Business" - ), - share: nil - ) - ] - """ + try await expect(model) { + try await model.$remindersLists.load() + } changes: { + $0.remindersLists[0].remindersList.title = "Personal" + $0.remindersLists[0].share = model.remindersLists[0].share + #expect($0.remindersLists[0].share?.recordID == share.recordID) } } } diff --git a/Examples/RemindersTests/SearchRemindersTests.swift b/Examples/RemindersTests/SearchRemindersTests.swift index aab566ef2..5f657aeb9 100644 --- a/Examples/RemindersTests/SearchRemindersTests.swift +++ b/Examples/RemindersTests/SearchRemindersTests.swift @@ -1,53 +1,42 @@ +import DebugSnapshots import Dependencies import DependenciesTestSupport +import Foundation import InlineSnapshotTesting +import SQLiteData import SnapshotTestingCustomDump import Testing @testable import Reminders extension BaseTestSuite { - @MainActor - @Suite( - .snapshots(record: .missing) - ) struct SearchRemindersTests { @Dependency(\.defaultDatabase) var database @Test func basics() async throws { let model = SearchRemindersModel() - try await model.$searchResults.load() - #expect(model.searchResults.completedCount == 0) - assertInlineSnapshot(of: model.searchResults.rows, as: .customDump) { - """ - [] - """ - } - - model.searchText = "Take" - try await model.searchTask?.value - #expect(model.searchResults.completedCount == 1) - assertInlineSnapshot(of: model.searchResults.rows, as: .customDump) { - """ - [ - [0]: SearchRemindersModel.Row( + try await expect(model) { + model.searchText = "Take" + try await model.searchTask?.value + } changes: { + $0.searchText = "Take" + $0.searchResults.completedCount = 1 + $0.searchResults.rows = [ + SearchRemindersModel.Row( isPastDue: false, notes: "", reminder: Reminder( - id: UUID(00000000-0000-0000-0000-00000000000A), - dueDate: Date(2009-02-17T23:31:30.000Z), - isFlagged: false, - notes: "", + id: UUID(10), + dueDate: Date(timeIntervalSince1970: 1_234_913_490), position: 8, priority: .high, - remindersListID: UUID(00000000-0000-0000-0000-000000000001), - status: .incomplete, + remindersListID: UUID(1), title: "Take out trash" ), remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000001), - color: 3985191935, + id: UUID(1), + color: .family, position: 2, title: "Family" ), @@ -55,99 +44,94 @@ extension BaseTestSuite { title: "**Take** out trash" ) ] - """ } } @Test func showCompleted() async throws { let model = SearchRemindersModel() - model.searchText = "Take" - try await model.showCompletedButtonTapped() - try await model.searchTask?.value - try await model.$searchResults.load() - assertInlineSnapshot(of: model.searchResults.rows, as: .customDump) { - """ - [ - [0]: SearchRemindersModel.Row( + try await expect(model) { + model.searchText = "Take" + try await model.showCompletedButtonTapped() + try await model.searchTask?.value + try await model.$searchResults.load() + } changes: { + $0.searchText = "Take" + $0.showCompletedInSearchResults = true + $0.searchResults.completedCount = 1 + $0.searchResults.rows = [ + SearchRemindersModel.Row( isPastDue: false, notes: "", reminder: Reminder( - id: UUID(00000000-0000-0000-0000-00000000000A), - dueDate: Date(2009-02-17T23:31:30.000Z), - isFlagged: false, - notes: "", + id: UUID(10), + dueDate: Date(timeIntervalSince1970: 1_234_913_490), position: 8, priority: .high, - remindersListID: UUID(00000000-0000-0000-0000-000000000001), - status: .incomplete, + remindersListID: UUID(1), title: "Take out trash" ), remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000001), - color: 3985191935, + id: UUID(1), + color: .family, position: 2, title: "Family" ), tags: "", title: "**Take** out trash" ), - [1]: SearchRemindersModel.Row( + SearchRemindersModel.Row( isPastDue: false, notes: "", reminder: Reminder( - id: UUID(00000000-0000-0000-0000-000000000006), - dueDate: Date(2008-08-07T23:31:30.000Z), - isFlagged: false, - notes: "", + id: UUID(6), + dueDate: Date(timeIntervalSince1970: 1_218_151_890), position: 4, - priority: nil, - remindersListID: UUID(00000000-0000-0000-0000-000000000000), + remindersListID: UUID(0), status: .completed, title: "Take a walk" ), remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000000), - color: 1218047999, + id: UUID(0), + color: .personal, position: 1, title: "Personal" ), tags: "#car #kids #social", title: "**Take** a walk" - ) + ), ] - """ } } @Test func deleteCompleted() async throws { let model = SearchRemindersModel() - model.searchText = "Take" - try await model.showCompletedButtonTapped() - model.deleteCompletedReminders() - try await model.searchTask?.value - try await model.$searchResults.load() - #expect(model.searchResults.completedCount == 0) - assertInlineSnapshot(of: model.searchResults.rows, as: .customDump) { - """ - [ - [0]: SearchRemindersModel.Row( + + try await expect(model) { + model.searchText = "Take" + try await model.showCompletedButtonTapped() + model.deleteCompletedReminders() + try await model.searchTask?.value + try await model.$searchResults.load() + } changes: { + $0.searchText = "Take" + $0.showCompletedInSearchResults = true + $0.searchResults.completedCount = 0 + $0.searchResults.rows = [ + SearchRemindersModel.Row( isPastDue: false, notes: "", reminder: Reminder( - id: UUID(00000000-0000-0000-0000-00000000000A), - dueDate: Date(2009-02-17T23:31:30.000Z), - isFlagged: false, - notes: "", + id: UUID(10), + dueDate: Date(timeIntervalSince1970: 1_234_913_490), position: 8, priority: .high, - remindersListID: UUID(00000000-0000-0000-0000-000000000001), - status: .incomplete, + remindersListID: UUID(1), title: "Take out trash" ), remindersList: RemindersList( - id: UUID(00000000-0000-0000-0000-000000000001), - color: 3985191935, + id: UUID(1), + color: .family, position: 2, title: "Family" ), @@ -155,7 +139,6 @@ extension BaseTestSuite { title: "**Take** out trash" ) ] - """ } } } diff --git a/Examples/RemindersTests/SeedTestData.swift b/Examples/RemindersTests/SeedTestData.swift new file mode 100644 index 000000000..eba800d06 --- /dev/null +++ b/Examples/RemindersTests/SeedTestData.swift @@ -0,0 +1,140 @@ +import Dependencies +import Foundation +import SQLiteData +import SwiftUI + +@testable import Reminders + +extension DatabaseWriter { + func seedTestData() throws { + @Dependency(\.date.now) var now + @Dependency(\.uuid) var uuid + try write { db in + var remindersListIDs: [UUID] = [] + for _ in 0...2 { + remindersListIDs.append(uuid()) + } + var reminderIDs: [UUID] = [] + for _ in 0...10 { + reminderIDs.append(uuid()) + } + try db.seed { + RemindersList( + id: remindersListIDs[0], + color: .personal, + title: "Personal" + ) + RemindersList( + id: remindersListIDs[1], + color: .family, + title: "Family" + ) + RemindersList( + id: remindersListIDs[2], + color: .business, + title: "Business" + ) + Reminder( + id: reminderIDs[0], + notes: "Milk\nEggs\nApples\nOatmeal\nSpinach", + remindersListID: remindersListIDs[0], + title: "Groceries" + ) + Reminder( + id: reminderIDs[1], + dueDate: now.addingTimeInterval(-60 * 60 * 24 * 2), + isFlagged: true, + remindersListID: remindersListIDs[0], + title: "Haircut" + ) + Reminder( + id: reminderIDs[2], + dueDate: now, + notes: "Ask about diet", + priority: .high, + remindersListID: remindersListIDs[0], + title: "Doctor appointment" + ) + Reminder( + id: reminderIDs[3], + dueDate: now.addingTimeInterval(-60 * 60 * 24 * 190), + remindersListID: remindersListIDs[0], + status: .completed, + title: "Take a walk" + ) + Reminder( + id: reminderIDs[4], + dueDate: now, + remindersListID: remindersListIDs[0], + title: "Buy concert tickets" + ) + Reminder( + id: reminderIDs[5], + dueDate: now.addingTimeInterval(60 * 60 * 24 * 2), + isFlagged: true, + priority: .high, + remindersListID: remindersListIDs[1], + title: "Pick up kids from school" + ) + Reminder( + id: reminderIDs[6], + dueDate: now.addingTimeInterval(-60 * 60 * 24 * 2), + priority: .low, + remindersListID: remindersListIDs[1], + status: .completed, + title: "Get laundry" + ) + Reminder( + id: reminderIDs[7], + dueDate: now.addingTimeInterval(60 * 60 * 24 * 4), + priority: .high, + remindersListID: remindersListIDs[1], + status: .incomplete, + title: "Take out trash" + ) + Reminder( + id: reminderIDs[8], + dueDate: now.addingTimeInterval(60 * 60 * 24 * 2), + notes: """ + Status of tax return + Expenses for next year + Changing payroll company + """, + remindersListID: remindersListIDs[2], + title: "Call accountant" + ) + Reminder( + id: reminderIDs[9], + dueDate: now.addingTimeInterval(-60 * 60 * 24 * 2), + priority: .medium, + remindersListID: remindersListIDs[2], + status: .completed, + title: "Send weekly emails" + ) + Reminder( + id: reminderIDs[10], + dueDate: now.addingTimeInterval(60 * 60 * 24 * 2), + remindersListID: remindersListIDs[2], + status: .incomplete, + title: "Prepare for WWDC" + ) + let tagIDs = ["car", "kids", "someday", "optional", "social", "night", "adulting"] + for tagID in tagIDs { + Tag(title: tagID) + } + ReminderTag.Draft(reminderID: reminderIDs[0], tagID: tagIDs[2]) + ReminderTag.Draft(reminderID: reminderIDs[0], tagID: tagIDs[3]) + ReminderTag.Draft(reminderID: reminderIDs[0], tagID: tagIDs[6]) + ReminderTag.Draft(reminderID: reminderIDs[1], tagID: tagIDs[2]) + ReminderTag.Draft(reminderID: reminderIDs[1], tagID: tagIDs[3]) + ReminderTag.Draft(reminderID: reminderIDs[2], tagID: tagIDs[6]) + ReminderTag.Draft(reminderID: reminderIDs[3], tagID: tagIDs[0]) + ReminderTag.Draft(reminderID: reminderIDs[3], tagID: tagIDs[1]) + ReminderTag.Draft(reminderID: reminderIDs[4], tagID: tagIDs[4]) + ReminderTag.Draft(reminderID: reminderIDs[3], tagID: tagIDs[4]) + ReminderTag.Draft(reminderID: reminderIDs[10], tagID: tagIDs[4]) + ReminderTag.Draft(reminderID: reminderIDs[4], tagID: tagIDs[5]) + } + } + } +} diff --git a/Examples/SyncUpTests/SyncUpFormTests.swift b/Examples/SyncUpTests/SyncUpFormTests.swift index c0f60e96f..562a596dc 100644 --- a/Examples/SyncUpTests/SyncUpFormTests.swift +++ b/Examples/SyncUpTests/SyncUpFormTests.swift @@ -1,12 +1,13 @@ +import DebugSnapshots import Dependencies import DependenciesTestSupport import Foundation +import SQLiteData import StructuredQueries import Testing @testable import SyncUps -@MainActor @Suite( .dependencies { try $0.bootstrapDatabase() @@ -21,11 +22,34 @@ struct SyncUpFormTests { @Test func saveNew() async throws { let draft = SyncUp.Draft(title: "Morning Sync") let model = SyncUpFormModel(syncUp: draft) - model.addAttendeeButtonTapped() - model.addAttendeeButtonTapped() + expect(model) { + $0.attendees = [SyncUpFormModel.AttendeeDraft(id: UUID(0))] + $0.focus = .title + $0.isDismissed = false + $0.syncUp = SyncUp.Draft(title: "Morning Sync") + } + + expect(model) { + model.addAttendeeButtonTapped() + } changes: { + $0.attendees.append(SyncUpFormModel.AttendeeDraft(id: UUID(1))) + $0.focus = .attendee(UUID(1)) + } + expect(model) { + model.addAttendeeButtonTapped() + } changes: { + $0.attendees.append(SyncUpFormModel.AttendeeDraft(id: UUID(2))) + $0.focus = .attendee(UUID(2)) + } + model.attendees[0].name = "Blob" model.attendees[1].name = "Blob Jr." - model.saveButtonTapped() + expect(model) { + model.saveButtonTapped() + } changes: { + $0.attendees.removeLast() + $0.isDismissed = true + } let syncUp = try await database.read { db in try #require(try SyncUp.order { $0.id.desc() }.fetchOne(db)) @@ -43,11 +67,44 @@ struct SyncUpFormTests { } let draft = SyncUp.Draft(existingSyncUp) let model = SyncUpFormModel(syncUp: draft) + expect(model) { + $0.attendees = [ + SyncUpFormModel.AttendeeDraft(id: UUID(0), name: "Blob"), + SyncUpFormModel.AttendeeDraft(id: UUID(1), name: "Blob Jr"), + SyncUpFormModel.AttendeeDraft(id: UUID(2), name: "Blob Sr"), + SyncUpFormModel.AttendeeDraft(id: UUID(3), name: "Blob Esq"), + SyncUpFormModel.AttendeeDraft(id: UUID(4), name: "Blob III"), + SyncUpFormModel.AttendeeDraft(id: UUID(5), name: "Blob I"), + ] + $0.focus = .title + $0.isDismissed = false + $0.syncUp = SyncUp.Draft( + id: UUID(1), + seconds: 60, + theme: .appOrange, + title: "Design" + ) + } + model.syncUp.title = "Evening Sync" - model.deleteAttendees(atOffsets: [1, 2, 3, 4, 5]) - model.addAttendeeButtonTapped() + expect(model) { + model.deleteAttendees(atOffsets: [1, 2, 3, 4, 5]) + } changes: { + $0.attendees.removeSubrange(1...5) + $0.focus = .attendee(UUID(0)) + } + expect(model) { + model.addAttendeeButtonTapped() + } changes: { + $0.attendees.append(SyncUpFormModel.AttendeeDraft(id: UUID(6))) + $0.focus = .attendee(UUID(6)) + } model.attendees[model.attendees.count - 1].name = "Blobby McBlob" - model.saveButtonTapped() + expect(model) { + model.saveButtonTapped() + } changes: { + $0.isDismissed = true + } let syncUp = try await database.read { db in try #require(try SyncUp.where { $0.id.eq(existingSyncUp.id) }.fetchOne(db)) diff --git a/Examples/SyncUps/App.swift b/Examples/SyncUps/App.swift index dffcd2bbd..648986c10 100644 --- a/Examples/SyncUps/App.swift +++ b/Examples/SyncUps/App.swift @@ -2,7 +2,6 @@ import CasePaths import SQLiteData import SwiftUI -@MainActor @Observable class AppModel { var path: [Path] { diff --git a/Examples/SyncUps/RecordMeeting.swift b/Examples/SyncUps/RecordMeeting.swift index 6b6620739..7ba8e2dae 100644 --- a/Examples/SyncUps/RecordMeeting.swift +++ b/Examples/SyncUps/RecordMeeting.swift @@ -4,7 +4,6 @@ import Speech import SwiftUI import SwiftUINavigation -@MainActor @Observable final class RecordMeetingModel: HashableObject { var alert: AlertState? diff --git a/Examples/SyncUps/Schema.swift b/Examples/SyncUps/Schema.swift index b806af404..6aa43db48 100644 --- a/Examples/SyncUps/Schema.swift +++ b/Examples/SyncUps/Schema.swift @@ -11,7 +11,7 @@ nonisolated struct SyncUp: Hashable, Identifiable { } @Table -nonisolated struct Attendee: Hashable, Identifiable { +nonisolated struct Attendee: Codable, Hashable, Identifiable { let id: UUID var name = "" var syncUpID: SyncUp.ID diff --git a/Examples/SyncUps/SyncUpDetail.swift b/Examples/SyncUps/SyncUpDetail.swift index 212f88cf0..b9b5aa439 100644 --- a/Examples/SyncUps/SyncUpDetail.swift +++ b/Examples/SyncUps/SyncUpDetail.swift @@ -2,7 +2,6 @@ import SQLiteData import SwiftUI import SwiftUINavigation -@MainActor @Observable final class SyncUpDetailModel: HashableObject { var destination: Destination? diff --git a/Examples/SyncUps/SyncUpForm.swift b/Examples/SyncUps/SyncUpForm.swift index 3cbfaf76d..325b55b9c 100644 --- a/Examples/SyncUps/SyncUpForm.swift +++ b/Examples/SyncUps/SyncUpForm.swift @@ -1,7 +1,9 @@ +import DebugSnapshots import SQLiteData import SwiftUI import SwiftUINavigation +@DebugSnapshot @Observable final class SyncUpFormModel: Identifiable { var attendees: [AttendeeDraft] = [] diff --git a/Examples/SyncUps/SyncUpsList.swift b/Examples/SyncUps/SyncUpsList.swift index 7630c7925..018515579 100644 --- a/Examples/SyncUps/SyncUpsList.swift +++ b/Examples/SyncUps/SyncUpsList.swift @@ -3,7 +3,6 @@ import SwiftUI import SwiftUINavigation import TipKit -@MainActor @Observable final class SyncUpsListModel { var addSyncUp: SyncUpFormModel?