From fae7a476a1c476ef2404319375f9ce399f2ca3b5 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Mon, 9 Feb 2026 20:37:52 +0100 Subject: [PATCH] Implemented the TodoGroup enumeration in the app target. --- App/Resources/Localizable.xcstrings | 44 +++++++++ App/Sources/Enumerations/TodoGroup.swift | 70 +++++++++++++ .../Tests/Enumerations/TodoGroupTests.swift | 99 +++++++++++++++++++ .../View Models/ContentViewModelTests.swift | 2 +- .../View Models/NewTaskViewModelTests.swift | 2 +- 5 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 App/Sources/Enumerations/TodoGroup.swift create mode 100644 UnitTests/Tests/Enumerations/TodoGroupTests.swift diff --git a/App/Resources/Localizable.xcstrings b/App/Resources/Localizable.xcstrings index c025f50..482e0bf 100644 --- a/App/Resources/Localizable.xcstrings +++ b/App/Resources/Localizable.xcstrings @@ -1,6 +1,50 @@ { "sourceLanguage" : "en", "strings" : { + "enumeration.todo-group.title.completed" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Completed" + } + } + } + }, + "enumeration.todo-group.title.overdue" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Overdue" + } + } + } + }, + "enumeration.todo-group.title.today" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Today" + } + } + } + }, + "enumeration.todo-group.title.upcoming" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Upcoming" + } + } + } + }, "view.new-task.navigation.title" : { "extractionState" : "manual", "localizations" : { diff --git a/App/Sources/Enumerations/TodoGroup.swift b/App/Sources/Enumerations/TodoGroup.swift new file mode 100644 index 0000000..ccf3ac2 --- /dev/null +++ b/App/Sources/Enumerations/TodoGroup.swift @@ -0,0 +1,70 @@ +import Foundation +import SwiftUI + +/// Categorizes todo tasks into groups based on their due dates and completion status. +/// +/// This enumeration provides a semantic grouping mechanism for organizing and filtering todo tasks throughout the application. +/// Each case represents a distinct category that helps users manage their tasks based on temporal relevance and completion state. +enum TodoGroup { + /// Tasks that have been marked as done, regardless of due date. + case completed + /// Tasks with due dates in the past that remain incomplete. + case overdue + /// Tasks due on the current day that are not yet completed. + case today + /// Tasks due in the future that are not yet completed. + case upcoming +} + +// MARK: - Computed + +extension TodoGroup { + + /// The color associated with the task group. + var color: Color { + switch self { + case .completed: .gray + case .overdue: .red + case .today: .blue + case .upcoming: .green + } + } + + /// The system icon name for the task group. + var iconName: String { + switch self { + case .completed: "checkmark.circle.fill" + case .overdue: "calendar.badge.exclamationmark" + case .today: "calendar.badge.clock" + case .upcoming: "calendar" + } + } + + /// The display title for the task group. + var title: LocalizedStringKey { + switch self { + case .completed: "enumeration.todo-group.title.completed" + case .overdue: "enumeration.todo-group.title.overdue" + case .today: "enumeration.todo-group.title.today" + case .upcoming: "enumeration.todo-group.title.upcoming" + + } + } + +} + +// MARK: - CaseIterable + +extension TodoGroup: CaseIterable { + + static var allCases: [TodoGroup] { [.today, .upcoming, .overdue, .completed] } + +} + +// MARK: - Identifiable + +extension TodoGroup: Identifiable { + + var id: Self { self } + +} diff --git a/UnitTests/Tests/Enumerations/TodoGroupTests.swift b/UnitTests/Tests/Enumerations/TodoGroupTests.swift new file mode 100644 index 0000000..e58058e --- /dev/null +++ b/UnitTests/Tests/Enumerations/TodoGroupTests.swift @@ -0,0 +1,99 @@ +import Foundation +import SwiftUI +import Testing + +@testable import Todos + +@Suite("TodoGroup enumeration tests") +struct TodoGroupTests { + + // MARK: Computed tests + + @Test( + "group color match expected values", + arguments: zip( + TodoGroup.allCases, + [Color.blue, .green, .red, .gray] + ) + ) + func color( + for group: TodoGroup, + expects expectation: Color + ) { + // GIVEN + // WHEN + let color = group.color + + // THEN + #expect(color == expectation) + } + + @Test( + "group icon names match expected values", + arguments: zip( + TodoGroup.allCases, + ["calendar.badge.clock", "calendar", "calendar.badge.exclamationmark", "checkmark.circle.fill"] + ) + ) + func iconName( + for group: TodoGroup, + expects expectation: String + ) { + // GIVEN + // WHEN + let iconName = group.iconName + + // THEN + #expect(iconName == expectation) + } + + @Test( + "group titles match expected values", + arguments: zip( + TodoGroup.allCases, + ["today", "upcoming", "overdue", "completed"] + ) + ) + func title( + for group: TodoGroup, + expects expectation: String + ) { + // GIVEN + let key = "enumeration.todo-group.title." + expectation + + // WHEN + let title = group.title + + // THEN + #expect(title == .init(key)) + } + + // MARK: Case Iteration Tests + + @Test("all cases contains all cases, in correct order") + func allCases() { + // GIVEN + // WHEN + let allCases = TodoGroup.allCases + + // THEN + #expect(allCases.count == 4) + #expect(allCases[0] == .today) + #expect(allCases[1] == .upcoming) + #expect(allCases[2] == .overdue) + #expect(allCases[3] == .completed) + } + + // MARK: Identifiable Tests + + @Test("id returns an identity of a case", arguments: TodoGroup.allCases) + func id(for group: TodoGroup) { + // GIVEN + // WHEN + let id = group.id + + // THEN + #expect(id == group) + } + +} diff --git a/UnitTests/Tests/View Models/ContentViewModelTests.swift b/UnitTests/Tests/View Models/ContentViewModelTests.swift index 668bd6e..adb8e25 100644 --- a/UnitTests/Tests/View Models/ContentViewModelTests.swift +++ b/UnitTests/Tests/View Models/ContentViewModelTests.swift @@ -4,7 +4,7 @@ import Testing @testable import Todos -@Suite("ContentView.ViewModel Tests") +@Suite("ContentView view model tests") struct ContentViewModelTests { // MARK: Initialization Tests diff --git a/UnitTests/Tests/View Models/NewTaskViewModelTests.swift b/UnitTests/Tests/View Models/NewTaskViewModelTests.swift index e33bc0c..12961b1 100644 --- a/UnitTests/Tests/View Models/NewTaskViewModelTests.swift +++ b/UnitTests/Tests/View Models/NewTaskViewModelTests.swift @@ -4,7 +4,7 @@ import Testing @testable import Todos -@Suite("NewTaskView ViewModel Tests") +@Suite("NewTaskView view model tests") struct NewTaskViewModelTests { // MARK: Initialization tests