TestingScenario.swift 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. //
  2. // TestingScenario.swift
  3. // LoopTestingKit
  4. //
  5. // Created by Michael Pangburn on 4/20/19.
  6. // Copyright © 2019 LoopKit Authors. All rights reserved.
  7. //
  8. import Foundation
  9. import LoopKit
  10. public struct ReloadManager: Codable {
  11. public let pump: Bool?
  12. public let cgm: Bool?
  13. }
  14. public struct TestingScenario {
  15. var dateRelativeGlucoseSamples: [DateRelativeGlucoseSample]
  16. var dateRelativeBasalEntries: [DateRelativeBasalEntry]
  17. var dateRelativeBolusEntries: [DateRelativeBolusEntry]
  18. var dateRelativeCarbEntries: [DateRelativeCarbEntry]
  19. var deviceActions: [DeviceAction]?
  20. var shouldReloadManager: ReloadManager?
  21. public func instantiate(relativeTo referenceDate: Date = Date()) -> TestingScenarioInstance {
  22. let glucoseSamples = dateRelativeGlucoseSamples
  23. .map { $0.newGlucoseSample(relativeTo: referenceDate) }
  24. let pastGlucoseSamples = glucoseSamples.filter { $0.date <= referenceDate }
  25. let futureGlucoseSamples = glucoseSamples.filter { $0.date > referenceDate }
  26. let basalEntries = dateRelativeBasalEntries.map { $0.newPumpEvent(relativeTo: referenceDate) }
  27. let bolusEntries = dateRelativeBolusEntries.map { $0.newPumpEvent(relativeTo: referenceDate) }
  28. let pumpEvents = (basalEntries + bolusEntries)
  29. .filter { $0.date <= referenceDate }
  30. .sorted(by: { $0.date < $1.date })
  31. let carbEntries = dateRelativeCarbEntries
  32. .filter { $0.enteredAt(relativeTo: referenceDate) <= referenceDate }
  33. .map { $0.newCarbEntry(relativeTo: referenceDate) }
  34. return TestingScenarioInstance(pastGlucoseSamples: pastGlucoseSamples, futureGlucoseSamples: futureGlucoseSamples, pumpEvents: pumpEvents, carbEntries: carbEntries, deviceActions: deviceActions ?? [], shouldReloadManager: shouldReloadManager)
  35. }
  36. public mutating func stepBackward(by offset: TimeInterval) {
  37. assert(offset > 0)
  38. shift(by: offset)
  39. }
  40. public mutating func stepForward(by offset: TimeInterval) {
  41. assert(offset > 0)
  42. shift(by: -offset)
  43. }
  44. public mutating func stepForward(
  45. unitsPerHour: Double,
  46. duration: TimeInterval,
  47. dateOffset: TimeInterval = 0,
  48. loopInterval: TimeInterval = 60 * 5 /* minutes */
  49. ) {
  50. precondition(duration > 0)
  51. dateRelativeBasalEntries.removeAll(where: { $0.dateOffset >= dateOffset })
  52. let basal = DateRelativeBasalEntry(unitsPerHourValue: unitsPerHour, dateOffset: dateOffset, duration: duration)
  53. dateRelativeBasalEntries.append(basal)
  54. stepForward(by: loopInterval)
  55. }
  56. mutating func shift(by offset: TimeInterval) {
  57. dateRelativeGlucoseSamples.mutateEach { $0.shift(by: offset) }
  58. dateRelativeBasalEntries.mutateEach { $0.shift(by: offset) }
  59. dateRelativeBolusEntries.mutateEach { $0.shift(by: offset) }
  60. dateRelativeCarbEntries.mutateEach { $0.shift(by: offset) }
  61. }
  62. }
  63. extension TestingScenario: Codable {
  64. public enum CodingKeys: String, CodingKey {
  65. case dateRelativeGlucoseSamples = "glucoseValues"
  66. case dateRelativeBasalEntries = "basalDoses"
  67. case dateRelativeBolusEntries = "bolusDoses"
  68. case dateRelativeCarbEntries = "carbEntries"
  69. case deviceActions = "deviceActions"
  70. case shouldReloadManager = "reloadManager"
  71. }
  72. }
  73. extension TestingScenario {
  74. public init(source: URL) throws {
  75. let decoder = JSONDecoder()
  76. let data = try Data(contentsOf: source)
  77. self = try decoder.decode(TestingScenario.self, from: data)
  78. }
  79. }