Add PlantGuide iOS app with plant identification and care management
- Implement camera capture and plant identification workflow - Add Core Data persistence for plants, care schedules, and cached API data - Create collection view with grid/list layouts and filtering - Build plant detail views with care information display - Integrate Trefle botanical API for plant care data - Add local image storage for captured plant photos - Implement dependency injection container for testability - Include accessibility support throughout the app Bug fixes in this commit: - Fix Trefle API decoding by removing duplicate CodingKeys - Fix LocalCachedImage to load from correct PlantImages directory - Set dateAdded when saving plants for proper collection sorting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
211
PlantGuideTests/TestFixtures/CareTask+TestFixtures.swift
Normal file
211
PlantGuideTests/TestFixtures/CareTask+TestFixtures.swift
Normal file
@@ -0,0 +1,211 @@
|
||||
//
|
||||
// CareTask+TestFixtures.swift
|
||||
// PlantGuideTests
|
||||
//
|
||||
// Test fixtures for CareTask entity - provides factory methods for
|
||||
// creating test instances with sensible defaults.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import PlantGuide
|
||||
|
||||
// MARK: - CareTask Test Fixtures
|
||||
|
||||
extension CareTask {
|
||||
|
||||
// MARK: - Factory Methods
|
||||
|
||||
/// Creates a mock care task with default values for testing
|
||||
/// - Parameters:
|
||||
/// - id: The task's unique identifier. Defaults to a new UUID.
|
||||
/// - plantID: ID of the plant this task belongs to. Defaults to a new UUID.
|
||||
/// - type: Type of care task. Defaults to .watering.
|
||||
/// - scheduledDate: When the task is scheduled. Defaults to tomorrow.
|
||||
/// - completedDate: When the task was completed. Defaults to nil (not completed).
|
||||
/// - notes: Additional notes. Defaults to empty string.
|
||||
/// - Returns: A configured CareTask instance for testing
|
||||
static func mock(
|
||||
id: UUID = UUID(),
|
||||
plantID: UUID = UUID(),
|
||||
type: CareTaskType = .watering,
|
||||
scheduledDate: Date = Calendar.current.date(byAdding: .day, value: 1, to: Date())!,
|
||||
completedDate: Date? = nil,
|
||||
notes: String = ""
|
||||
) -> CareTask {
|
||||
CareTask(
|
||||
id: id,
|
||||
plantID: plantID,
|
||||
type: type,
|
||||
scheduledDate: scheduledDate,
|
||||
completedDate: completedDate,
|
||||
notes: notes
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock watering task
|
||||
/// - Parameters:
|
||||
/// - plantID: ID of the plant this task belongs to
|
||||
/// - scheduledDate: When the task is scheduled. Defaults to tomorrow.
|
||||
/// - completedDate: When the task was completed. Defaults to nil.
|
||||
/// - Returns: A watering task
|
||||
static func mockWatering(
|
||||
id: UUID = UUID(),
|
||||
plantID: UUID = UUID(),
|
||||
scheduledDate: Date = Calendar.current.date(byAdding: .day, value: 1, to: Date())!,
|
||||
completedDate: Date? = nil
|
||||
) -> CareTask {
|
||||
mock(
|
||||
id: id,
|
||||
plantID: plantID,
|
||||
type: .watering,
|
||||
scheduledDate: scheduledDate,
|
||||
completedDate: completedDate,
|
||||
notes: "Water with moderate amount"
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock fertilizing task
|
||||
/// - Parameters:
|
||||
/// - plantID: ID of the plant this task belongs to
|
||||
/// - scheduledDate: When the task is scheduled. Defaults to next week.
|
||||
/// - completedDate: When the task was completed. Defaults to nil.
|
||||
/// - Returns: A fertilizing task
|
||||
static func mockFertilizing(
|
||||
id: UUID = UUID(),
|
||||
plantID: UUID = UUID(),
|
||||
scheduledDate: Date = Calendar.current.date(byAdding: .day, value: 7, to: Date())!,
|
||||
completedDate: Date? = nil
|
||||
) -> CareTask {
|
||||
mock(
|
||||
id: id,
|
||||
plantID: plantID,
|
||||
type: .fertilizing,
|
||||
scheduledDate: scheduledDate,
|
||||
completedDate: completedDate,
|
||||
notes: "Apply balanced fertilizer"
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock repotting task
|
||||
/// - Parameters:
|
||||
/// - plantID: ID of the plant this task belongs to
|
||||
/// - scheduledDate: When the task is scheduled. Defaults to next month.
|
||||
/// - Returns: A repotting task
|
||||
static func mockRepotting(
|
||||
id: UUID = UUID(),
|
||||
plantID: UUID = UUID(),
|
||||
scheduledDate: Date = Calendar.current.date(byAdding: .month, value: 1, to: Date())!
|
||||
) -> CareTask {
|
||||
mock(
|
||||
id: id,
|
||||
plantID: plantID,
|
||||
type: .repotting,
|
||||
scheduledDate: scheduledDate,
|
||||
notes: "Move to larger pot with fresh soil"
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock pruning task
|
||||
/// - Parameters:
|
||||
/// - plantID: ID of the plant this task belongs to
|
||||
/// - scheduledDate: When the task is scheduled. Defaults to next week.
|
||||
/// - Returns: A pruning task
|
||||
static func mockPruning(
|
||||
id: UUID = UUID(),
|
||||
plantID: UUID = UUID(),
|
||||
scheduledDate: Date = Calendar.current.date(byAdding: .day, value: 14, to: Date())!
|
||||
) -> CareTask {
|
||||
mock(
|
||||
id: id,
|
||||
plantID: plantID,
|
||||
type: .pruning,
|
||||
scheduledDate: scheduledDate,
|
||||
notes: "Remove dead leaves and shape plant"
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock pest control task
|
||||
/// - Parameters:
|
||||
/// - plantID: ID of the plant this task belongs to
|
||||
/// - scheduledDate: When the task is scheduled. Defaults to tomorrow.
|
||||
/// - Returns: A pest control task
|
||||
static func mockPestControl(
|
||||
id: UUID = UUID(),
|
||||
plantID: UUID = UUID(),
|
||||
scheduledDate: Date = Calendar.current.date(byAdding: .day, value: 1, to: Date())!
|
||||
) -> CareTask {
|
||||
mock(
|
||||
id: id,
|
||||
plantID: plantID,
|
||||
type: .pestControl,
|
||||
scheduledDate: scheduledDate,
|
||||
notes: "Apply neem oil treatment"
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates an overdue task (scheduled in the past, not completed)
|
||||
static func mockOverdue(
|
||||
plantID: UUID = UUID(),
|
||||
daysOverdue: Int = 3
|
||||
) -> CareTask {
|
||||
mock(
|
||||
plantID: plantID,
|
||||
type: .watering,
|
||||
scheduledDate: Calendar.current.date(byAdding: .day, value: -daysOverdue, to: Date())!,
|
||||
completedDate: nil,
|
||||
notes: "Overdue watering task"
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a completed task
|
||||
static func mockCompleted(
|
||||
plantID: UUID = UUID(),
|
||||
type: CareTaskType = .watering
|
||||
) -> CareTask {
|
||||
let scheduledDate = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
|
||||
return mock(
|
||||
plantID: plantID,
|
||||
type: type,
|
||||
scheduledDate: scheduledDate,
|
||||
completedDate: Date(),
|
||||
notes: "Completed task"
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a future task scheduled for a specific number of days ahead
|
||||
static func mockFuture(
|
||||
plantID: UUID = UUID(),
|
||||
type: CareTaskType = .watering,
|
||||
daysAhead: Int = 7
|
||||
) -> CareTask {
|
||||
mock(
|
||||
plantID: plantID,
|
||||
type: type,
|
||||
scheduledDate: Calendar.current.date(byAdding: .day, value: daysAhead, to: Date())!
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates an array of watering tasks for the next several weeks
|
||||
static func mockWeeklyWateringTasks(
|
||||
plantID: UUID = UUID(),
|
||||
weeks: Int = 4
|
||||
) -> [CareTask] {
|
||||
(0..<weeks).map { weekIndex in
|
||||
let scheduledDate = Calendar.current.date(
|
||||
byAdding: .day,
|
||||
value: (weekIndex + 1) * 7,
|
||||
to: Date()
|
||||
)!
|
||||
return mockWatering(plantID: plantID, scheduledDate: scheduledDate)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a set of mixed tasks for a single plant
|
||||
static func mockMixedTasks(plantID: UUID = UUID()) -> [CareTask] {
|
||||
[
|
||||
mockWatering(plantID: plantID),
|
||||
mockFertilizing(plantID: plantID),
|
||||
mockPruning(plantID: plantID)
|
||||
]
|
||||
}
|
||||
}
|
||||
212
PlantGuideTests/TestFixtures/Plant+TestFixtures.swift
Normal file
212
PlantGuideTests/TestFixtures/Plant+TestFixtures.swift
Normal file
@@ -0,0 +1,212 @@
|
||||
//
|
||||
// Plant+TestFixtures.swift
|
||||
// PlantGuideTests
|
||||
//
|
||||
// Test fixtures for Plant entity - provides factory methods for creating
|
||||
// test instances with sensible defaults.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import PlantGuide
|
||||
|
||||
// MARK: - Plant Test Fixtures
|
||||
|
||||
extension Plant {
|
||||
|
||||
// MARK: - Factory Methods
|
||||
|
||||
/// Creates a mock plant with default values for testing
|
||||
/// - Parameters:
|
||||
/// - id: The plant's unique identifier. Defaults to a new UUID.
|
||||
/// - scientificName: Scientific name. Defaults to "Monstera deliciosa".
|
||||
/// - commonNames: Array of common names. Defaults to ["Swiss Cheese Plant"].
|
||||
/// - family: Botanical family. Defaults to "Araceae".
|
||||
/// - genus: Botanical genus. Defaults to "Monstera".
|
||||
/// - imageURLs: Remote image URLs. Defaults to empty.
|
||||
/// - dateIdentified: When plant was identified. Defaults to current date.
|
||||
/// - identificationSource: Source of identification. Defaults to .onDeviceML.
|
||||
/// - localImagePaths: Local storage paths. Defaults to empty.
|
||||
/// - dateAdded: When added to collection. Defaults to nil.
|
||||
/// - confidenceScore: Identification confidence. Defaults to 0.95.
|
||||
/// - notes: User notes. Defaults to nil.
|
||||
/// - isFavorite: Favorite status. Defaults to false.
|
||||
/// - customName: User-assigned name. Defaults to nil.
|
||||
/// - location: Plant location. Defaults to nil.
|
||||
/// - Returns: A configured Plant instance for testing
|
||||
static func mock(
|
||||
id: UUID = UUID(),
|
||||
scientificName: String = "Monstera deliciosa",
|
||||
commonNames: [String] = ["Swiss Cheese Plant"],
|
||||
family: String = "Araceae",
|
||||
genus: String = "Monstera",
|
||||
imageURLs: [URL] = [],
|
||||
dateIdentified: Date = Date(),
|
||||
identificationSource: IdentificationSource = .onDeviceML,
|
||||
localImagePaths: [String] = [],
|
||||
dateAdded: Date? = nil,
|
||||
confidenceScore: Double? = 0.95,
|
||||
notes: String? = nil,
|
||||
isFavorite: Bool = false,
|
||||
customName: String? = nil,
|
||||
location: String? = nil
|
||||
) -> Plant {
|
||||
Plant(
|
||||
id: id,
|
||||
scientificName: scientificName,
|
||||
commonNames: commonNames,
|
||||
family: family,
|
||||
genus: genus,
|
||||
imageURLs: imageURLs,
|
||||
dateIdentified: dateIdentified,
|
||||
identificationSource: identificationSource,
|
||||
localImagePaths: localImagePaths,
|
||||
dateAdded: dateAdded,
|
||||
confidenceScore: confidenceScore,
|
||||
notes: notes,
|
||||
isFavorite: isFavorite,
|
||||
customName: customName,
|
||||
location: location
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock Monstera plant
|
||||
static func mockMonstera(
|
||||
id: UUID = UUID(),
|
||||
isFavorite: Bool = false
|
||||
) -> Plant {
|
||||
mock(
|
||||
id: id,
|
||||
scientificName: "Monstera deliciosa",
|
||||
commonNames: ["Swiss Cheese Plant", "Monstera"],
|
||||
family: "Araceae",
|
||||
genus: "Monstera",
|
||||
isFavorite: isFavorite
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock Pothos plant
|
||||
static func mockPothos(
|
||||
id: UUID = UUID(),
|
||||
isFavorite: Bool = false
|
||||
) -> Plant {
|
||||
mock(
|
||||
id: id,
|
||||
scientificName: "Epipremnum aureum",
|
||||
commonNames: ["Pothos", "Devil's Ivy", "Golden Pothos"],
|
||||
family: "Araceae",
|
||||
genus: "Epipremnum",
|
||||
isFavorite: isFavorite
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock Snake Plant
|
||||
static func mockSnakePlant(
|
||||
id: UUID = UUID(),
|
||||
isFavorite: Bool = false
|
||||
) -> Plant {
|
||||
mock(
|
||||
id: id,
|
||||
scientificName: "Sansevieria trifasciata",
|
||||
commonNames: ["Snake Plant", "Mother-in-law's Tongue"],
|
||||
family: "Asparagaceae",
|
||||
genus: "Sansevieria",
|
||||
isFavorite: isFavorite
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock Peace Lily plant
|
||||
static func mockPeaceLily(
|
||||
id: UUID = UUID(),
|
||||
isFavorite: Bool = false
|
||||
) -> Plant {
|
||||
mock(
|
||||
id: id,
|
||||
scientificName: "Spathiphyllum wallisii",
|
||||
commonNames: ["Peace Lily", "Spathe Flower"],
|
||||
family: "Araceae",
|
||||
genus: "Spathiphyllum",
|
||||
isFavorite: isFavorite
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock Fiddle Leaf Fig plant
|
||||
static func mockFiddleLeafFig(
|
||||
id: UUID = UUID(),
|
||||
isFavorite: Bool = false
|
||||
) -> Plant {
|
||||
mock(
|
||||
id: id,
|
||||
scientificName: "Ficus lyrata",
|
||||
commonNames: ["Fiddle Leaf Fig", "Fiddle-leaf Fig"],
|
||||
family: "Moraceae",
|
||||
genus: "Ficus",
|
||||
isFavorite: isFavorite
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates an array of mock plants for collection testing
|
||||
static func mockCollection(count: Int = 5) -> [Plant] {
|
||||
var plants: [Plant] = []
|
||||
let generators: [() -> Plant] = [
|
||||
{ .mockMonstera() },
|
||||
{ .mockPothos() },
|
||||
{ .mockSnakePlant() },
|
||||
{ .mockPeaceLily() },
|
||||
{ .mockFiddleLeafFig() }
|
||||
]
|
||||
|
||||
for i in 0..<count {
|
||||
plants.append(generators[i % generators.count]())
|
||||
}
|
||||
return plants
|
||||
}
|
||||
|
||||
/// Creates a plant with an image URL for caching tests
|
||||
static func mockWithImages(
|
||||
id: UUID = UUID(),
|
||||
imageCount: Int = 3
|
||||
) -> Plant {
|
||||
let imageURLs = (0..<imageCount).map { index in
|
||||
URL(string: "https://example.com/images/plant_\(id.uuidString)_\(index).jpg")!
|
||||
}
|
||||
return mock(
|
||||
id: id,
|
||||
imageURLs: imageURLs
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a plant with local image paths for storage tests
|
||||
static func mockWithLocalImages(
|
||||
id: UUID = UUID(),
|
||||
imageCount: Int = 2
|
||||
) -> Plant {
|
||||
let localPaths = (0..<imageCount).map { index in
|
||||
"\(id.uuidString)/image_\(index).jpg"
|
||||
}
|
||||
return mock(
|
||||
id: id,
|
||||
localImagePaths: localPaths
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a fully populated plant with all optional fields
|
||||
static func mockComplete(id: UUID = UUID()) -> Plant {
|
||||
mock(
|
||||
id: id,
|
||||
scientificName: "Monstera deliciosa",
|
||||
commonNames: ["Swiss Cheese Plant", "Monstera", "Split-leaf Philodendron"],
|
||||
family: "Araceae",
|
||||
genus: "Monstera",
|
||||
imageURLs: [URL(string: "https://example.com/monstera.jpg")!],
|
||||
dateIdentified: Date(),
|
||||
identificationSource: .plantNetAPI,
|
||||
localImagePaths: ["\(id.uuidString)/captured.jpg"],
|
||||
dateAdded: Date(),
|
||||
confidenceScore: 0.98,
|
||||
notes: "Needs regular watering and indirect light",
|
||||
isFavorite: true,
|
||||
customName: "My Beautiful Monstera",
|
||||
location: "Living room by the window"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// PlantCareSchedule+TestFixtures.swift
|
||||
// PlantGuideTests
|
||||
//
|
||||
// Test fixtures for PlantCareSchedule entity - provides factory methods for
|
||||
// creating test instances with sensible defaults.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import PlantGuide
|
||||
|
||||
// MARK: - PlantCareSchedule Test Fixtures
|
||||
|
||||
extension PlantCareSchedule {
|
||||
|
||||
// MARK: - Factory Methods
|
||||
|
||||
/// Creates a mock care schedule with default values for testing
|
||||
/// - Parameters:
|
||||
/// - id: The schedule's unique identifier. Defaults to a new UUID.
|
||||
/// - plantID: ID of the plant this schedule belongs to. Defaults to a new UUID.
|
||||
/// - lightRequirement: Light needs. Defaults to .partialShade.
|
||||
/// - wateringSchedule: Watering description. Defaults to "Weekly".
|
||||
/// - temperatureRange: Safe temp range. Defaults to 18...26.
|
||||
/// - fertilizerSchedule: Fertilizer description. Defaults to "Monthly".
|
||||
/// - tasks: Array of care tasks. Defaults to empty.
|
||||
/// - Returns: A configured PlantCareSchedule instance for testing
|
||||
static func mock(
|
||||
id: UUID = UUID(),
|
||||
plantID: UUID = UUID(),
|
||||
lightRequirement: LightRequirement = .partialShade,
|
||||
wateringSchedule: String = "Weekly",
|
||||
temperatureRange: ClosedRange<Int> = 18...26,
|
||||
fertilizerSchedule: String = "Monthly",
|
||||
tasks: [CareTask] = []
|
||||
) -> PlantCareSchedule {
|
||||
PlantCareSchedule(
|
||||
id: id,
|
||||
plantID: plantID,
|
||||
lightRequirement: lightRequirement,
|
||||
wateringSchedule: wateringSchedule,
|
||||
temperatureRange: temperatureRange,
|
||||
fertilizerSchedule: fertilizerSchedule,
|
||||
tasks: tasks
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock schedule with watering tasks
|
||||
/// - Parameters:
|
||||
/// - plantID: ID of the plant this schedule belongs to
|
||||
/// - taskCount: Number of watering tasks to generate. Defaults to 4.
|
||||
/// - startDate: Starting date for first task. Defaults to tomorrow.
|
||||
/// - Returns: A schedule with generated watering tasks
|
||||
static func mockWithWateringTasks(
|
||||
plantID: UUID = UUID(),
|
||||
taskCount: Int = 4,
|
||||
startDate: Date = Calendar.current.date(byAdding: .day, value: 1, to: Date())!
|
||||
) -> PlantCareSchedule {
|
||||
let tasks = (0..<taskCount).map { index in
|
||||
CareTask.mockWatering(
|
||||
plantID: plantID,
|
||||
scheduledDate: Calendar.current.date(byAdding: .day, value: index * 7, to: startDate)!
|
||||
)
|
||||
}
|
||||
return mock(
|
||||
plantID: plantID,
|
||||
wateringSchedule: "Every 7 days",
|
||||
tasks: tasks
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock schedule with mixed care tasks
|
||||
/// - Parameters:
|
||||
/// - plantID: ID of the plant this schedule belongs to
|
||||
/// - Returns: A schedule with watering and fertilizing tasks
|
||||
static func mockWithMixedTasks(plantID: UUID = UUID()) -> PlantCareSchedule {
|
||||
let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date())!
|
||||
let nextWeek = Calendar.current.date(byAdding: .day, value: 7, to: Date())!
|
||||
let nextMonth = Calendar.current.date(byAdding: .day, value: 30, to: Date())!
|
||||
|
||||
let tasks: [CareTask] = [
|
||||
.mockWatering(plantID: plantID, scheduledDate: tomorrow),
|
||||
.mockWatering(plantID: plantID, scheduledDate: nextWeek),
|
||||
.mockFertilizing(plantID: plantID, scheduledDate: nextMonth)
|
||||
]
|
||||
|
||||
return mock(
|
||||
plantID: plantID,
|
||||
wateringSchedule: "Weekly",
|
||||
fertilizerSchedule: "Monthly during growing season",
|
||||
tasks: tasks
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock schedule for a tropical plant (high humidity, frequent watering)
|
||||
static func mockTropical(plantID: UUID = UUID()) -> PlantCareSchedule {
|
||||
mock(
|
||||
plantID: plantID,
|
||||
lightRequirement: .partialShade,
|
||||
wateringSchedule: "Every 3 days",
|
||||
temperatureRange: 20...30,
|
||||
fertilizerSchedule: "Biweekly during growing season"
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock schedule for a succulent (low water, full sun)
|
||||
static func mockSucculent(plantID: UUID = UUID()) -> PlantCareSchedule {
|
||||
mock(
|
||||
plantID: plantID,
|
||||
lightRequirement: .fullSun,
|
||||
wateringSchedule: "Every 14 days",
|
||||
temperatureRange: 15...35,
|
||||
fertilizerSchedule: "Monthly during spring and summer"
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock schedule for a shade-loving plant
|
||||
static func mockShadePlant(plantID: UUID = UUID()) -> PlantCareSchedule {
|
||||
mock(
|
||||
plantID: plantID,
|
||||
lightRequirement: .lowLight,
|
||||
wateringSchedule: "Weekly",
|
||||
temperatureRange: 16...24,
|
||||
fertilizerSchedule: "Every 6 weeks"
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock schedule with overdue tasks
|
||||
static func mockWithOverdueTasks(plantID: UUID = UUID()) -> PlantCareSchedule {
|
||||
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
|
||||
let lastWeek = Calendar.current.date(byAdding: .day, value: -7, to: Date())!
|
||||
let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date())!
|
||||
|
||||
let tasks: [CareTask] = [
|
||||
.mockWatering(plantID: plantID, scheduledDate: lastWeek), // Overdue
|
||||
.mockWatering(plantID: plantID, scheduledDate: yesterday), // Overdue
|
||||
.mockWatering(plantID: plantID, scheduledDate: tomorrow) // Upcoming
|
||||
]
|
||||
|
||||
return mock(
|
||||
plantID: plantID,
|
||||
tasks: tasks
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a mock schedule with completed tasks
|
||||
static func mockWithCompletedTasks(plantID: UUID = UUID()) -> PlantCareSchedule {
|
||||
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
|
||||
let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date())!
|
||||
let nextWeek = Calendar.current.date(byAdding: .day, value: 7, to: Date())!
|
||||
|
||||
let tasks: [CareTask] = [
|
||||
.mockWatering(plantID: plantID, scheduledDate: yesterday, completedDate: yesterday),
|
||||
.mockWatering(plantID: plantID, scheduledDate: tomorrow),
|
||||
.mockWatering(plantID: plantID, scheduledDate: nextWeek)
|
||||
]
|
||||
|
||||
return mock(
|
||||
plantID: plantID,
|
||||
tasks: tasks
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user