diff --git a/App/Sources/Extensions/TodoFetchDescriptor+Inits.swift b/App/Sources/Extensions/TodoFetchDescriptor+Inits.swift index 0136396..ad3382d 100644 --- a/App/Sources/Extensions/TodoFetchDescriptor+Inits.swift +++ b/App/Sources/Extensions/TodoFetchDescriptor+Inits.swift @@ -19,36 +19,50 @@ extension FetchDescriptor where T == Todo { /// /// - Parameters: /// - group: The todo group category to filter by. + /// - showCompleted: Whether to include completed tasks. Only applies to groups other than `.completed`. /// - calendar: The calendar to use for date calculations. Defaults to `.current`. init( group: TodoGroup, + showCompleted: Bool, calendar: Calendar = .current ) { + let predicate: Predicate let today = calendar.startOfDay(for: .now) let tomorrow = calendar.date(byAdding: .day, value: 1, to: today) ?? today switch group { case .completed: - self.init( - predicate: #Predicate { $0.completed != nil }, - sortBy: [.init(\.completed, order: .reverse)] - ) + predicate = #Predicate { $0.completed != nil } case .overdue: - self.init( - predicate: #Predicate { $0.completed == nil && $0.due < today }, - sortBy: [.init(\.due, order: .reverse)] - ) + predicate = showCompleted + ? #Predicate { $0.due < today } + : #Predicate { $0.completed == nil && $0.due < today } case .today: - self.init( - predicate: #Predicate { $0.completed == nil && $0.due >= today && $0.due < tomorrow }, - sortBy: [.init(\.due, order: .forward)] - ) + predicate = showCompleted + ? #Predicate { $0.due >= today && $0.due < tomorrow } + : #Predicate { $0.completed == nil && $0.due >= today && $0.due < tomorrow } case .upcoming: - self.init( - predicate: #Predicate { $0.completed == nil && $0.due >= tomorrow }, - sortBy: [.init(\.due, order: .forward)] - ) + predicate = showCompleted + ? #Predicate { $0.due >= tomorrow } + : #Predicate { $0.completed == nil && $0.due >= tomorrow } } + + let sortDescriptors: [SortDescriptor] = + switch group { + case .completed: + [.init(\Todo.completed, order: .reverse)] + case .overdue: + [.init(\Todo.due, order: .reverse)] + case .today: + [.init(\Todo.due, order: .forward)] + case .upcoming: + [.init(\Todo.due, order: .forward)] + } + + self.init( + predicate: predicate, + sortBy: sortDescriptors + ) } } diff --git a/UnitTests/Tests/Extensions/TodoFetchDescriptorTests.swift b/UnitTests/Tests/Extensions/TodoFetchDescriptorTests.swift index 68d6ddf..9a521cb 100644 --- a/UnitTests/Tests/Extensions/TodoFetchDescriptorTests.swift +++ b/UnitTests/Tests/Extensions/TodoFetchDescriptorTests.swift @@ -20,7 +20,10 @@ struct TodoFetchDescriptorTests { let context = container.mainContext // WHEN - let descriptor = FetchDescriptor(group: .today) + let descriptor = FetchDescriptor( + group: .today, + showCompleted: .random() + ) let results = try context.fetch(descriptor) // THEN @@ -28,7 +31,7 @@ struct TodoFetchDescriptorTests { } @Test( - "initializes with group when filled tasks", + "initializes with group and show completed disabled when filled tasks", arguments: TodoGroup.allCases ) @MainActor @@ -40,7 +43,10 @@ struct TodoFetchDescriptorTests { insert(into: context) // WHEN - let descriptor = FetchDescriptor(group: group) + let descriptor = FetchDescriptor( + group: group, + showCompleted: false + ) let results = try context.fetch(descriptor) // THEN @@ -61,6 +67,50 @@ struct TodoFetchDescriptorTests { #expect(results[1].title == "Upcoming task #2") } } + + @Test( + "initializes with group and show completed enabled when filled tasks", + arguments: TodoGroup.allCases + ) + @MainActor + func initializationWithShowCompleted(for group: TodoGroup) throws { + // GIVEN + let container = try modelContainer + let context = container.mainContext + + insert(into: context) + + // WHEN + let descriptor = FetchDescriptor( + group: group, + showCompleted: true + ) + let results = try context.fetch(descriptor) + + // THEN + if group == .overdue || group == .upcoming { + #expect(results.count == 3) + } else { + #expect(results.count == 2) + } + + switch group { + case .completed: + #expect(results[0].title == "Completed task #2") + #expect(results[1].title == "Completed task #1") + case .overdue: + #expect(results[0].title == "Completed task #1") + #expect(results[1].title == "Overdue task #2") + #expect(results[2].title == "Overdue task #1") + case .today: + #expect(results[0].title == "Today task #1") + #expect(results[1].title == "Today task #2") + case .upcoming: + #expect(results[0].title == "Upcoming task #1") + #expect(results[1].title == "Upcoming task #2") + #expect(results[2].title == "Completed task #2") + } + } }