Skip to content

Commit eaf3244

Browse files
committed
lots of tests
1 parent 0c0285b commit eaf3244

11 files changed

Lines changed: 1018 additions & 63 deletions

File tree

Examples/Examples.xcodeproj/project.pbxproj

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
CA14DBC92DA884C400E36852 /* CasePaths in Frameworks */ = {isa = PBXBuildFile; productRef = CA14DBC82DA884C400E36852 /* CasePaths */; };
1111
CA2908C92D4AF70E003F165F /* UIKitNavigation in Frameworks */ = {isa = PBXBuildFile; productRef = CA2908C82D4AF70E003F165F /* UIKitNavigation */; };
1212
CA5E46912DEBB8570069E0F8 /* SwiftUINavigation in Frameworks */ = {isa = PBXBuildFile; productRef = CA5E46902DEBB8570069E0F8 /* SwiftUINavigation */; };
13+
CA5E47072DECEF0F0069E0F8 /* InlineSnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = CA5E47062DECEF0F0069E0F8 /* InlineSnapshotTesting */; };
14+
CA5E47092DECEFC80069E0F8 /* SnapshotTestingCustomDump in Frameworks */ = {isa = PBXBuildFile; productRef = CA5E47082DECEFC80069E0F8 /* SnapshotTestingCustomDump */; };
15+
CA5E470B2DECF0280069E0F8 /* DependenciesTestSupport in Frameworks */ = {isa = PBXBuildFile; productRef = CA5E470A2DECF0280069E0F8 /* DependenciesTestSupport */; };
1316
CAD001872D874F1F00FA977A /* DependenciesTestSupport in Frameworks */ = {isa = PBXBuildFile; productRef = CAD001862D874F1F00FA977A /* DependenciesTestSupport */; };
1417
CAFDD64A2D5E823A00EE099E /* SharingGRDB in Frameworks */ = {isa = PBXBuildFile; productRef = CAFDD6492D5E823A00EE099E /* SharingGRDB */; };
1518
DC5FA7482D4C63D60082743E /* DependenciesMacros in Frameworks */ = {isa = PBXBuildFile; productRef = DC5FA7472D4C63D60082743E /* DependenciesMacros */; };
@@ -125,6 +128,9 @@
125128
isa = PBXFrameworksBuildPhase;
126129
buildActionMask = 2147483647;
127130
files = (
131+
CA5E47092DECEFC80069E0F8 /* SnapshotTestingCustomDump in Frameworks */,
132+
CA5E47072DECEF0F0069E0F8 /* InlineSnapshotTesting in Frameworks */,
133+
CA5E470B2DECF0280069E0F8 /* DependenciesTestSupport in Frameworks */,
128134
);
129135
runOnlyForDeploymentPostprocessing = 0;
130136
};
@@ -232,6 +238,9 @@
232238
);
233239
name = RemindersTests;
234240
packageProductDependencies = (
241+
CA5E47062DECEF0F0069E0F8 /* InlineSnapshotTesting */,
242+
CA5E47082DECEFC80069E0F8 /* SnapshotTestingCustomDump */,
243+
CA5E470A2DECF0280069E0F8 /* DependenciesTestSupport */,
235244
);
236245
productName = RemindersTests;
237246
productReference = CA5E46962DEBFE410069E0F8 /* RemindersTests.xctest */;
@@ -405,6 +414,7 @@
405414
DCBE8A122D4842BF0071F499 /* XCRemoteSwiftPackageReference "swift-case-paths" */,
406415
DCF267372D48437300B680BE /* XCRemoteSwiftPackageReference "swift-navigation" */,
407416
DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */,
417+
CA5E47052DECEF0F0069E0F8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
408418
);
409419
preferredProjectObjectVersion = 77;
410420
productRefGroup = CAF836992D4735620047AEB5 /* Products */;
@@ -986,6 +996,14 @@
986996
/* End XCConfigurationList section */
987997

988998
/* Begin XCRemoteSwiftPackageReference section */
999+
CA5E47052DECEF0F0069E0F8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = {
1000+
isa = XCRemoteSwiftPackageReference;
1001+
repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing.git";
1002+
requirement = {
1003+
kind = upToNextMajorVersion;
1004+
minimumVersion = 1.18.4;
1005+
};
1006+
};
9891007
DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */ = {
9901008
isa = XCRemoteSwiftPackageReference;
9911009
repositoryURL = "https://github.com/pointfreeco/swift-dependencies";
@@ -1028,6 +1046,21 @@
10281046
package = DCF267372D48437300B680BE /* XCRemoteSwiftPackageReference "swift-navigation" */;
10291047
productName = SwiftUINavigation;
10301048
};
1049+
CA5E47062DECEF0F0069E0F8 /* InlineSnapshotTesting */ = {
1050+
isa = XCSwiftPackageProductDependency;
1051+
package = CA5E47052DECEF0F0069E0F8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */;
1052+
productName = InlineSnapshotTesting;
1053+
};
1054+
CA5E47082DECEFC80069E0F8 /* SnapshotTestingCustomDump */ = {
1055+
isa = XCSwiftPackageProductDependency;
1056+
package = CA5E47052DECEF0F0069E0F8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */;
1057+
productName = SnapshotTestingCustomDump;
1058+
};
1059+
CA5E470A2DECF0280069E0F8 /* DependenciesTestSupport */ = {
1060+
isa = XCSwiftPackageProductDependency;
1061+
package = DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */;
1062+
productName = DependenciesTestSupport;
1063+
};
10311064
CAD001862D874F1F00FA977A /* DependenciesTestSupport */ = {
10321065
isa = XCSwiftPackageProductDependency;
10331066
package = DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */;

Examples/Reminders/RemindersDetail.swift

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import SwiftUINavigation
66
@MainActor
77
@Observable
88
class RemindersDetailModel: HashableObject {
9-
@ObservationIgnored @FetchAll var reminderStates: [Row]
9+
@ObservationIgnored @FetchAll var reminderRows: [Row]
1010
@ObservationIgnored @Shared var ordering: Ordering
1111
@ObservationIgnored @Shared var showCompleted: Bool
1212

@@ -22,7 +22,7 @@ class RemindersDetailModel: HashableObject {
2222
wrappedValue: detailType == .completed,
2323
.appStorage("show_completed_list_\(detailType.id)")
2424
)
25-
_reminderStates = FetchAll(remindersQuery)
25+
_reminderRows = FetchAll(remindersQuery)
2626
}
2727

2828
func orderingButtonTapped(_ ordering: Ordering) async {
@@ -35,10 +35,10 @@ class RemindersDetailModel: HashableObject {
3535
await updateQuery()
3636
}
3737

38-
func move(from source: IndexSet, to destination: Int) {
38+
func move(from source: IndexSet, to destination: Int) async {
3939
withErrorReporting {
4040
try database.write { db in
41-
var ids = reminderStates.map(\.reminder.id)
41+
var ids = reminderRows.map(\.reminder.id)
4242
ids.move(fromOffsets: source, toOffset: destination)
4343
try Reminder
4444
.where { $0.id.in(ids) }
@@ -56,11 +56,12 @@ class RemindersDetailModel: HashableObject {
5656
}
5757
}
5858
$ordering.withLock { $0 = .manual }
59+
await updateQuery()
5960
}
6061

6162
private func updateQuery() async {
6263
await withErrorReporting {
63-
try await $reminderStates.load(remindersQuery, animation: .default)
64+
try await $reminderRows.load(remindersQuery, animation: .default)
6465
}
6566
}
6667

@@ -162,18 +163,20 @@ struct RemindersDetailView: View {
162163
}
163164
}
164165
.listRowSeparator(.hidden)
165-
ForEach(model.reminderStates) { reminderState in
166+
ForEach(model.reminderRows) { row in
166167
ReminderRow(
167168
color: model.detailType.color,
168-
isPastDue: reminderState.isPastDue,
169-
notes: reminderState.notes,
170-
reminder: reminderState.reminder,
171-
remindersList: reminderState.remindersList,
169+
isPastDue: row.isPastDue,
170+
notes: row.notes,
171+
reminder: row.reminder,
172+
remindersList: row.remindersList,
172173
showCompleted: model.showCompleted,
173-
tags: reminderState.tags
174+
tags: row.tags
174175
)
175176
}
176-
.onMove(perform: model.move(from:to:))
177+
.onMove { source, destination in
178+
Task { await model.move(from: source, to: destination) }
179+
}
177180
}
178181
.onScrollGeometryChange(for: Bool.self) { geometry in
179182
geometry.contentOffset.y + geometry.contentInsets.top > navigationTitleHeight

Examples/Reminders/Schema.swift

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ struct Reminder: Codable, Equatable, Identifiable {
2222
var isCompleted = false
2323
var isFlagged = false
2424
var notes = ""
25+
var position = 0
2526
var priority: Priority?
2627
var remindersListID: RemindersList.ID
27-
var position = 0
2828
var title = ""
2929
}
3030

@@ -57,10 +57,10 @@ extension Reminder {
5757

5858
extension Reminder.TableColumns {
5959
var isPastDue: some QueryExpression<Bool> {
60-
!isCompleted && #sql("coalesce(date(\(dueDate)) < date('now'), 0)")
60+
!isCompleted && #sql("coalesce(date(\(dueDate)) < now(), 0)")
6161
}
6262
var isToday: some QueryExpression<Bool> {
63-
!isCompleted && #sql("coalesce(date(\(dueDate)) = date('now'), 0)")
63+
!isCompleted && #sql("coalesce(date(\(dueDate)) = now(), 0)")
6464
}
6565
var isScheduled: some QueryExpression<Bool> {
6666
!isCompleted && dueDate.isNot(nil)
@@ -104,13 +104,26 @@ func appDatabase() throws -> any DatabaseWriter {
104104
}
105105
}
106106
#endif
107+
db.add(
108+
function: DatabaseFunction("now", argumentCount: 0) { _ in
109+
@Dependency(\.date.now) var now
110+
return now.formatted(
111+
.iso8601.year().month().day()
112+
.dateTimeSeparator(.space)
113+
.time(includingFractionalSeconds: true)
114+
)
115+
}
116+
)
107117
}
108-
if context == .live {
109-
let path = URL.documentsDirectory.appending(component: "db.sqlite").path()
118+
if context == .preview {
119+
database = try DatabaseQueue(configuration: configuration)
120+
} else {
121+
let path =
122+
context == .live
123+
? URL.documentsDirectory.appending(component: "db.sqlite").path()
124+
: URL.temporaryDirectory.appending(component: "\(UUID().uuidString)-db.sqlite").path()
110125
logger.info("open \(path)")
111126
database = try DatabasePool(path: path, configuration: configuration)
112-
} else {
113-
database = try DatabaseQueue(configuration: configuration)
114127
}
115128
var migrator = DatabaseMigrator()
116129
#if DEBUG
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import Foundation
2+
import SharingGRDB
3+
import SwiftUI
4+
import Testing
5+
6+
@testable import Reminders
7+
8+
@Suite(
9+
.dependencies {
10+
$0.date.now = Date(timeIntervalSince1970: 1234567890)
11+
$0.defaultDatabase = try Reminders.appDatabase()
12+
try $0.defaultDatabase.write { try $0.seedTestData() }
13+
},
14+
.snapshots(record: .failed)
15+
)
16+
struct BaseTestSuite {}
17+
18+
extension Database {
19+
func seedTestData() throws {
20+
let baseDate = Date(timeIntervalSince1970: 1234567890)
21+
try seed {
22+
RemindersList(
23+
id: UUID(0),
24+
color: Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255),
25+
position: 0,
26+
title: "Personal"
27+
)
28+
RemindersList(
29+
id: UUID(1),
30+
color: Color(red: 0xed / 255, green: 0x89 / 255, blue: 0x35 / 255),
31+
position: 1,
32+
title: "Family"
33+
)
34+
RemindersList(
35+
id: UUID(2),
36+
color: Color(red: 0xb2 / 255, green: 0x5d / 255, blue: 0xd3 / 255),
37+
position: 2,
38+
title: "Business"
39+
)
40+
Reminder(
41+
id: UUID(0),
42+
notes: "Milk\nEggs\nApples\nOatmeal\nSpinach",
43+
position: 0,
44+
remindersListID: UUID(0),
45+
title: "Groceries"
46+
)
47+
Reminder(
48+
id: UUID(1),
49+
dueDate: baseDate.addingTimeInterval(-60 * 60 * 24 * 2),
50+
isFlagged: true,
51+
position: 1,
52+
remindersListID: UUID(0),
53+
title: "Haircut"
54+
)
55+
Reminder(
56+
id: UUID(2),
57+
dueDate: baseDate,
58+
notes: "Ask about diet",
59+
position: 2,
60+
priority: .high,
61+
remindersListID: UUID(0),
62+
title: "Doctor appointment"
63+
)
64+
Reminder(
65+
id: UUID(3),
66+
dueDate: baseDate.addingTimeInterval(-60 * 60 * 24 * 190),
67+
isCompleted: true,
68+
position: 3,
69+
remindersListID: UUID(0),
70+
title: "Take a walk"
71+
)
72+
Reminder(
73+
id: UUID(4),
74+
dueDate: baseDate,
75+
position: 4,
76+
remindersListID: UUID(0),
77+
title: "Buy concert tickets"
78+
)
79+
Reminder(
80+
id: UUID(5),
81+
dueDate: baseDate.addingTimeInterval(60 * 60 * 24 * 2),
82+
isFlagged: true,
83+
position: 5,
84+
priority: .high,
85+
remindersListID: UUID(1),
86+
title: "Pick up kids from school"
87+
)
88+
Reminder(
89+
id: UUID(6),
90+
dueDate: baseDate.addingTimeInterval(-60 * 60 * 24 * 2),
91+
isCompleted: true,
92+
position: 6,
93+
priority: .low,
94+
remindersListID: UUID(1),
95+
title: "Get laundry"
96+
)
97+
Reminder(
98+
id: UUID(7),
99+
dueDate: baseDate.addingTimeInterval(60 * 60 * 24 * 4),
100+
isCompleted: false,
101+
position: 7,
102+
priority: .high,
103+
remindersListID: UUID(1),
104+
title: "Take out trash"
105+
)
106+
Reminder(
107+
id: UUID(8),
108+
dueDate: baseDate.addingTimeInterval(60 * 60 * 24 * 2),
109+
notes: """
110+
Status of tax return
111+
Expenses for next year
112+
Changing payroll company
113+
""",
114+
position: 8,
115+
remindersListID: UUID(2),
116+
title: "Call accountant"
117+
)
118+
Reminder(
119+
id: UUID(9),
120+
dueDate: baseDate.addingTimeInterval(-60 * 60 * 24 * 2),
121+
isCompleted: true,
122+
position: 9,
123+
priority: .medium,
124+
remindersListID: UUID(2),
125+
title: "Send weekly emails"
126+
)
127+
Reminder(
128+
id: UUID(10),
129+
dueDate: baseDate.addingTimeInterval(60 * 60 * 24 * 2),
130+
isCompleted: false,
131+
position: 10,
132+
remindersListID: UUID(2),
133+
title: "Prepare for WWDC"
134+
)
135+
Tag(id: UUID(0), title: "car")
136+
Tag(id: UUID(1), title: "kids")
137+
Tag(id: UUID(2), title: "someday")
138+
Tag(id: UUID(3), title: "optional")
139+
Tag(id: UUID(4), title: "social")
140+
Tag(id: UUID(5), title: "night")
141+
Tag(id: UUID(6), title: "adulting")
142+
ReminderTag(reminderID: UUID(0), tagID: UUID(2))
143+
ReminderTag(reminderID: UUID(0), tagID: UUID(3))
144+
ReminderTag(reminderID: UUID(0), tagID: UUID(6))
145+
ReminderTag(reminderID: UUID(1), tagID: UUID(2))
146+
ReminderTag(reminderID: UUID(1), tagID: UUID(3))
147+
ReminderTag(reminderID: UUID(2), tagID: UUID(6))
148+
ReminderTag(reminderID: UUID(3), tagID: UUID(0))
149+
ReminderTag(reminderID: UUID(3), tagID: UUID(1))
150+
ReminderTag(reminderID: UUID(4), tagID: UUID(4))
151+
ReminderTag(reminderID: UUID(3), tagID: UUID(4))
152+
ReminderTag(reminderID: UUID(10), tagID: UUID(4))
153+
ReminderTag(reminderID: UUID(4), tagID: UUID(5))
154+
}
155+
}
156+
}

0 commit comments

Comments
 (0)