import Foundation import SwiftData import Testing @testable import Todos @Suite("FetchDescriptor extension tests") struct TodoFetchDescriptorTests { // MARK: Initialization tests @Test( "initializes with group when empty tasks", arguments: TodoGroup.allCases ) @MainActor func initializationWhenEmptyTasks(for group: TodoGroup) throws { // GIVEN let container = try modelContainer let context = container.mainContext // WHEN let descriptor = FetchDescriptor( group: .today, showCompleted: .random() ) let results = try context.fetch(descriptor) // THEN #expect(results.isEmpty) } @Test( "initializes with group and show completed disabled when filled tasks", arguments: TodoGroup.allCases ) @MainActor func initializationWhenFilledTasks(for group: TodoGroup) throws { // GIVEN let container = try modelContainer let context = container.mainContext insert(into: context) // WHEN let descriptor = FetchDescriptor( group: group, showCompleted: false ) let results = try context.fetch(descriptor) // THEN #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 == "Overdue task #2") #expect(results[1].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") } } @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") } } } // MARK: - Helpers private extension TodoFetchDescriptorTests { // MARK: Computed var modelContainer: ModelContainer { get throws { try ModelContainer( for: Todo.self, configurations: .init(isStoredInMemoryOnly: true) ) } } // MARK: Functions func insert( into context: ModelContext, calendar: Calendar = .current ) { let tasks: [Todo] = [ .init( title: "Today task #1", due: .now ), .init( title: "Today task #2", due: .now ), .init( title: "Upcoming task #1", due: calendar.date(byAdding: .day, value: 1, to: .now) ?? .now ), .init( title: "Upcoming task #2", due: calendar.date(byAdding: .day, value: 1, to: .now) ?? .now ), .init( title: "Overdue task #1", due: calendar.date(byAdding: .day, value: -1, to: .now) ?? .now ), .init( title: "Overdue task #2", due: calendar.date(byAdding: .day, value: -1, to: .now) ?? .now ), .init( title: "Completed task #1", due: calendar.date(byAdding: .day, value: -1, to: .now) ?? .now, completed: .now ), .init( title: "Completed task #2", due: calendar.date(byAdding: .day, value: 1, to: .now) ?? .now, completed: .now ) ] for task in tasks { context.insert(task) } } }