|
|
@@ -23,7 +23,7 @@ import Testing
|
|
|
NetworkAssembly(),
|
|
|
UIAssembly(),
|
|
|
SecurityAssembly(),
|
|
|
- TestAssembly(testContext: testContext) // Add our test assembly last to override CarbsStorage
|
|
|
+ TestAssembly(testContext: testContext)
|
|
|
])
|
|
|
|
|
|
resolver = assembler.resolver
|
|
|
@@ -31,15 +31,178 @@ import Testing
|
|
|
}
|
|
|
|
|
|
@Test("Storage is correctly initialized") func testStorageInitialization() {
|
|
|
- // Verify storage exists
|
|
|
#expect(storage != nil, "CarbsStorage should be injected")
|
|
|
+ #expect(storage is BaseCarbsStorage, "Storage should be of type BaseCarbsStorage")
|
|
|
+ #expect(storage.updatePublisher != nil, "Update publisher should be available")
|
|
|
+ }
|
|
|
|
|
|
- // Verify it's the correct type
|
|
|
- #expect(
|
|
|
- storage is BaseCarbsStorage, "Storage should be of type BaseCarbsStorage"
|
|
|
+ @Test("Store and retrieve carbs entries") func testStoreAndRetrieveCarbs() async throws {
|
|
|
+ // Given
|
|
|
+ let testEntries = [
|
|
|
+ CarbsEntry(
|
|
|
+ id: UUID().uuidString,
|
|
|
+ createdAt: Date(),
|
|
|
+ actualDate: Date(),
|
|
|
+ carbs: 20,
|
|
|
+ fat: 0,
|
|
|
+ protein: 0,
|
|
|
+ note: "Test meal",
|
|
|
+ enteredBy: "Test",
|
|
|
+ isFPU: false,
|
|
|
+ fpuID: nil
|
|
|
+ )
|
|
|
+ ]
|
|
|
+
|
|
|
+ // When
|
|
|
+ try await storage.storeCarbs(testEntries, areFetchedFromRemote: false)
|
|
|
+ let recentEntries = try await CoreDataStack.shared.fetchEntitiesAsync(
|
|
|
+ ofType: CarbEntryStored.self,
|
|
|
+ onContext: testContext,
|
|
|
+ predicate: NSPredicate(format: "TRUEPREDICATE"),
|
|
|
+ key: "date",
|
|
|
+ ascending: false
|
|
|
)
|
|
|
|
|
|
- // Verify we can access the update publisher
|
|
|
- #expect(storage.updatePublisher != nil, "Update publisher should be available")
|
|
|
+ guard let recentEntries = recentEntries as? [CarbEntryStored] else {
|
|
|
+ throw TestError("Failed to get recent entries")
|
|
|
+ }
|
|
|
+
|
|
|
+ // Then
|
|
|
+ #expect(!recentEntries.isEmpty, "Should have stored entries")
|
|
|
+ #expect(recentEntries.count == 1, "Should have exactly one entry")
|
|
|
+ #expect(recentEntries[0].carbs == 20, "Carbs value should match")
|
|
|
+ #expect(recentEntries[0].fat == 0, "Fat value should match")
|
|
|
+ #expect(recentEntries[0].protein == 0, "Protein value should match")
|
|
|
+ #expect(recentEntries[0].note == "Test meal", "Note should match")
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Delete carbs entry") func testDeleteCarbsEntry() async throws {
|
|
|
+ // Given
|
|
|
+ let testEntry = CarbsEntry(
|
|
|
+ id: UUID().uuidString,
|
|
|
+ createdAt: Date(),
|
|
|
+ actualDate: Date(),
|
|
|
+ carbs: 30,
|
|
|
+ fat: nil,
|
|
|
+ protein: nil,
|
|
|
+ note: "Delete test",
|
|
|
+ enteredBy: "Test",
|
|
|
+ isFPU: false,
|
|
|
+ fpuID: nil
|
|
|
+ )
|
|
|
+
|
|
|
+ // When
|
|
|
+ try await storage.storeCarbs([testEntry], areFetchedFromRemote: false)
|
|
|
+
|
|
|
+ // Get the stored entry's ObjectID
|
|
|
+ let storedEntries = try await CoreDataStack.shared.fetchEntitiesAsync(
|
|
|
+ ofType: CarbEntryStored.self,
|
|
|
+ onContext: testContext,
|
|
|
+ predicate: NSPredicate(format: "carbs == 30"),
|
|
|
+ key: "date",
|
|
|
+ ascending: false
|
|
|
+ ) as? [CarbEntryStored]
|
|
|
+
|
|
|
+ guard let objectID = storedEntries?.first?.objectID else {
|
|
|
+ throw TestError("Failed to get stored entry's ObjectID")
|
|
|
+ }
|
|
|
+
|
|
|
+ // Delete the entry
|
|
|
+ await storage.deleteCarbsEntryStored(objectID)
|
|
|
+
|
|
|
+ // Then - verify deletion
|
|
|
+ let remainingEntries = try await CoreDataStack.shared.fetchEntitiesAsync(
|
|
|
+ ofType: CarbEntryStored.self,
|
|
|
+ onContext: testContext,
|
|
|
+ predicate: NSPredicate(format: "carbs == 30"),
|
|
|
+ key: "date",
|
|
|
+ ascending: false
|
|
|
+ ) as? [CarbEntryStored]
|
|
|
+
|
|
|
+ #expect(remainingEntries?.isEmpty == true, "Should have no entries after deletion")
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Get carbs not yet uploaded to Nightscout") func testGetCarbsNotYetUploadedToNightscout() async throws {
|
|
|
+ // Given
|
|
|
+ let testEntry = CarbsEntry(
|
|
|
+ id: UUID().uuidString,
|
|
|
+ createdAt: Date(),
|
|
|
+ actualDate: Date(),
|
|
|
+ carbs: 40,
|
|
|
+ fat: nil,
|
|
|
+ protein: nil,
|
|
|
+ note: "NS test",
|
|
|
+ enteredBy: "Test",
|
|
|
+ isFPU: false,
|
|
|
+ fpuID: nil
|
|
|
+ )
|
|
|
+
|
|
|
+ // When
|
|
|
+ try await storage.storeCarbs([testEntry], areFetchedFromRemote: false)
|
|
|
+ let notUploadedEntries = try await storage.getCarbsNotYetUploadedToNightscout()
|
|
|
+
|
|
|
+ // Then
|
|
|
+ #expect(!notUploadedEntries.isEmpty, "Should have entries not uploaded to NS")
|
|
|
+ #expect(notUploadedEntries[0].carbs == 40, "Carbs value should match")
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Get FPUs not yet uploaded to Nightscout") func testGetFPUsNotYetUploadedToNightscout() async throws {
|
|
|
+ // Given
|
|
|
+ let fpuID = UUID().uuidString
|
|
|
+ let testEntry = CarbsEntry(
|
|
|
+ id: UUID().uuidString,
|
|
|
+ createdAt: Date(),
|
|
|
+ actualDate: Date(),
|
|
|
+ carbs: 30,
|
|
|
+ fat: 20,
|
|
|
+ protein: 10,
|
|
|
+ note: "FPU test",
|
|
|
+ enteredBy: "Test",
|
|
|
+ isFPU: false,
|
|
|
+ fpuID: fpuID
|
|
|
+ )
|
|
|
+
|
|
|
+ // When
|
|
|
+ try await storage.storeCarbs([testEntry], areFetchedFromRemote: false)
|
|
|
+
|
|
|
+ // First verify all stored entries
|
|
|
+ let allStoredEntries = try await CoreDataStack.shared.fetchEntitiesAsync(
|
|
|
+ ofType: CarbEntryStored.self,
|
|
|
+ onContext: testContext,
|
|
|
+ predicate: NSPredicate(format: "fpuID == %@", fpuID),
|
|
|
+ key: "date",
|
|
|
+ ascending: true
|
|
|
+ ) as? [CarbEntryStored]
|
|
|
+
|
|
|
+ // Then verify the stored entries
|
|
|
+ #expect(allStoredEntries?.isEmpty == false, "Should have stored entries")
|
|
|
+ #expect(allStoredEntries?.count ?? 0 > 1, "Should have multiple entries due to FPU splitting")
|
|
|
+
|
|
|
+ // Original carb-non-fpu entry should be stored with original fat and protein values and isFPU set to false
|
|
|
+ let carbNonFpuEntry = allStoredEntries?.first(where: { $0.isFPU == false })
|
|
|
+ #expect(carbNonFpuEntry != nil, "Should have one carb non-fpu entry")
|
|
|
+ #expect(carbNonFpuEntry?.carbs == 30, "Original carbs should match")
|
|
|
+ #expect(carbNonFpuEntry?.protein == 10, "Original carbs should match")
|
|
|
+ #expect(carbNonFpuEntry?.fat == 20, "Original carbs should match")
|
|
|
+
|
|
|
+ // Additional carb-fpu entries should be created for fat/protein with isFPU set to true and the carbs set to the amount of each carbEquivalent
|
|
|
+ let carbFpuEntry = allStoredEntries?.filter { $0.isFPU == true }
|
|
|
+ #expect(carbFpuEntry?.isEmpty == false, "Should have additional carb-fpu entries")
|
|
|
+
|
|
|
+ // Now test the Nightscout upload function
|
|
|
+ let notUploadedFPUs = try await storage.getFPUsNotYetUploadedToNightscout()
|
|
|
+
|
|
|
+ // Then verify Nightscout entries
|
|
|
+ #expect(!notUploadedFPUs.isEmpty, "Should have FPUs not uploaded to NS")
|
|
|
+ let fpu = notUploadedFPUs[0]
|
|
|
+ #expect(fpu.carbs ?? 0 < 30, "Original carbs value should match")
|
|
|
+ #expect(fpu.protein == 0, "Protein value should match")
|
|
|
+ #expect(fpu.fat == 0, "Fat value should match")
|
|
|
+
|
|
|
+ // Verify all entries share the same fpuID
|
|
|
+ #expect(
|
|
|
+ allStoredEntries?.allSatisfy { $0.fpuID?.uuidString == fpuID } == true,
|
|
|
+ "All entries should share the same fpuID"
|
|
|
+ )
|
|
|
}
|
|
|
}
|