ForecastedGlucoseEvaluatorTests.swift 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import Foundation
  2. import Testing
  3. @testable import Trio
  4. @Suite("Trio Alerts: ForecastedGlucoseEvaluator") struct ForecastedGlucoseEvaluatorTests {
  5. /// Builds a `Determination` defaulting every non-predictions field, varying only `predictions`.
  6. private func makeDetermination(predictions: Predictions?) -> Determination {
  7. Determination(
  8. id: nil,
  9. reason: "",
  10. units: nil,
  11. insulinReq: nil,
  12. eventualBG: nil,
  13. sensitivityRatio: nil,
  14. rate: nil,
  15. duration: nil,
  16. iob: nil,
  17. cob: nil,
  18. predictions: predictions,
  19. deliverAt: nil,
  20. carbsReq: nil,
  21. temp: nil,
  22. bg: nil,
  23. reservoir: nil,
  24. isf: nil,
  25. timestamp: nil,
  26. tdd: nil,
  27. current_target: nil,
  28. minDelta: nil,
  29. expectedDelta: nil,
  30. minGuardBG: nil,
  31. minPredBG: nil,
  32. threshold: nil,
  33. carbRatio: nil,
  34. received: nil
  35. )
  36. }
  37. @Test("Reduces to min across all four curves at default horizon (+20min, index 4)") func minAcrossAllFourCurves() {
  38. let predictions = Predictions(
  39. iob: [100, 101, 102, 103, 104],
  40. zt: [130, 131, 132, 133, 99],
  41. cob: [110, 111, 112, 113, 90],
  42. uam: [120, 121, 122, 123, 95]
  43. )
  44. let determination = makeDetermination(predictions: predictions)
  45. let result = ForecastedGlucoseEvaluator.evaluate(determination: determination)
  46. #expect(result != nil)
  47. #expect(result?.predictedGlucose == Decimal(90))
  48. #expect(result?.horizonMinutes == 20)
  49. #expect(result?.curvesUsed == Set([.iob, .cob, .uam, .zt]))
  50. #expect(result?.perCurve[.iob] == Decimal(104))
  51. #expect(result?.perCurve[.cob] == Decimal(90))
  52. #expect(result?.perCurve[.uam] == Decimal(95))
  53. #expect(result?.perCurve[.zt] == Decimal(99))
  54. }
  55. @Test("nil predictions returns nil") func nilPredictionsReturnsNil() {
  56. let determination = makeDetermination(predictions: nil)
  57. #expect(ForecastedGlucoseEvaluator.evaluate(determination: determination) == nil)
  58. }
  59. @Test("All curves shorter than the horizon index returns nil") func indexOutOfBoundsAllShortReturnsNil() {
  60. let predictions = Predictions(
  61. iob: [100, 101, 102],
  62. zt: [130, 131, 132],
  63. cob: [110, 111, 112],
  64. uam: [120, 121, 122]
  65. )
  66. let determination = makeDetermination(predictions: predictions)
  67. #expect(ForecastedGlucoseEvaluator.evaluate(determination: determination) == nil)
  68. }
  69. @Test("Only one populated curve is used") func onlyOneCurvePopulated() {
  70. let predictions = Predictions(
  71. iob: [80, 81, 82, 83, 84],
  72. zt: nil,
  73. cob: nil,
  74. uam: nil
  75. )
  76. let determination = makeDetermination(predictions: predictions)
  77. let result = ForecastedGlucoseEvaluator.evaluate(determination: determination)
  78. #expect(result != nil)
  79. #expect(result?.predictedGlucose == Decimal(84))
  80. #expect(result?.curvesUsed == Set([.iob]))
  81. }
  82. @Test("Non-default horizon selects the matching index") func nonDefaultHorizonSelectsCorrectIndex() {
  83. let predictions = Predictions(
  84. iob: [100, 90, 80, 70],
  85. zt: nil,
  86. cob: [105, 95, 85, 75],
  87. uam: nil
  88. )
  89. let determination = makeDetermination(predictions: predictions)
  90. let result = ForecastedGlucoseEvaluator.evaluate(determination: determination, horizonMinutes: 10)
  91. #expect(result != nil)
  92. #expect(result?.predictedGlucose == Decimal(80))
  93. #expect(result?.curvesUsed == Set([.iob, .cob]))
  94. #expect(result?.horizonMinutes == 10)
  95. }
  96. @Test("Curves with differing lengths skip those missing the index") func differingLengthsSomeMissing() {
  97. let predictions = Predictions(
  98. iob: [100, 101, 102, 103, 104],
  99. zt: [130, 131, 132],
  100. cob: [110, 111],
  101. uam: [120, 121, 122, 123, 70]
  102. )
  103. let determination = makeDetermination(predictions: predictions)
  104. let result = ForecastedGlucoseEvaluator.evaluate(determination: determination)
  105. #expect(result != nil)
  106. #expect(result?.predictedGlucose == Decimal(70))
  107. #expect(result?.curvesUsed == Set([.iob, .uam]))
  108. }
  109. @Test("All-empty arrays return nil") func emptyArraysReturnNil() {
  110. let predictions = Predictions(iob: [], zt: [], cob: [], uam: [])
  111. let determination = makeDetermination(predictions: predictions)
  112. #expect(ForecastedGlucoseEvaluator.evaluate(determination: determination) == nil)
  113. }
  114. }