| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- import CoreData
- import Foundation
- import Swinject
- import Testing
- @testable import Trio
- @Suite("CarbsStorage Tests", .serialized) struct CarbsStorageTests: Injectable {
- @Injected() var storage: CarbsStorage!
- let resolver: Resolver
- var coreDataStack: CoreDataStack!
- var testContext: NSManagedObjectContext!
- init() async throws {
- // Create test context
- coreDataStack = try await CoreDataStack.createForTests()
- testContext = coreDataStack.newTaskContext()
- // Create assembler with test assembly
- let assembler = Assembler([
- StorageAssembly(),
- ServiceAssembly(),
- APSAssembly(),
- NetworkAssembly(),
- UIAssembly(),
- SecurityAssembly(),
- TestAssembly(testContext: testContext)
- ])
- resolver = assembler.resolver
- injectServices(resolver)
- }
- @Test("Storage is correctly initialized") func testStorageInitialization() {
- #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")
- }
- @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.fetchEntitiesAsync(
- ofType: CarbEntryStored.self,
- onContext: testContext,
- predicate: NSPredicate(format: "TRUEPREDICATE"),
- key: "date",
- ascending: false
- )
- 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.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.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.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"
- )
- }
- }
|