@@ -27,8 +27,8 @@ class MockDelegate: LoopDataManagerDelegate {
27
27
self . recommendation = automaticDose. recommendation
28
28
completion ( error)
29
29
}
30
- func roundBasalRate( unitsPerHour: Double ) -> Double { unitsPerHour }
31
- func roundBolusVolume( units: Double ) -> Double { units }
30
+ func roundBasalRate( unitsPerHour: Double ) -> Double { Double ( Int ( unitsPerHour / 0.05 ) ) * 0.05 }
31
+ func roundBolusVolume( units: Double ) -> Double { Double ( Int ( units / 0.05 ) ) * 0.05 }
32
32
var pumpManagerStatus : PumpManagerStatus ?
33
33
var cgmManagerStatus : CGMManagerStatus ?
34
34
var pumpStatusHighlight : DeviceStatusHighlight ?
@@ -331,7 +331,7 @@ class LoopDataManagerDosingTests: LoopDataManagerTests {
331
331
}
332
332
loopDataManager. loop ( )
333
333
wait ( for: [ exp] , timeout: 1.0 )
334
- let expectedAutomaticDoseRecommendation = AutomaticDoseRecommendation ( basalAdjustment: TempBasalRecommendation ( unitsPerHour: 4.577747629410191 , duration: . minutes( 30 ) ) )
334
+ let expectedAutomaticDoseRecommendation = AutomaticDoseRecommendation ( basalAdjustment: TempBasalRecommendation ( unitsPerHour: 4.55 , duration: . minutes( 30 ) ) )
335
335
XCTAssertEqual ( delegate. recommendation, expectedAutomaticDoseRecommendation)
336
336
XCTAssertEqual ( dosingDecisionStore. dosingDecisions. count, 1 )
337
337
if dosingDecisionStore. dosingDecisions. count == 1 {
@@ -355,7 +355,7 @@ class LoopDataManagerDosingTests: LoopDataManagerTests {
355
355
}
356
356
loopDataManager. loop ( )
357
357
wait ( for: [ exp] , timeout: 1.0 )
358
- let expectedAutomaticDoseRecommendation = AutomaticDoseRecommendation ( basalAdjustment: TempBasalRecommendation ( unitsPerHour: 4.577747629410191 , duration: . minutes( 30 ) ) )
358
+ let expectedAutomaticDoseRecommendation = AutomaticDoseRecommendation ( basalAdjustment: TempBasalRecommendation ( unitsPerHour: 4.55 , duration: . minutes( 30 ) ) )
359
359
XCTAssertNil ( delegate. recommendation)
360
360
XCTAssertEqual ( dosingDecisionStore. dosingDecisions. count, 1 )
361
361
XCTAssertEqual ( dosingDecisionStore. dosingDecisions [ 0 ] . reason, " loop " )
@@ -456,4 +456,81 @@ class LoopDataManagerDosingTests: LoopDataManagerTests {
456
456
waitOnMain ( timeout: 5 )
457
457
XCTAssertNil ( mockDelegate. recommendation)
458
458
}
459
+
460
+ func testAutoBolusMaxIOBClamping( ) {
461
+ /// `maximumBolus` is set to clamp the automatic dose
462
+ /// Autobolus without clamping: 0.65 U. Clamped recommendation: 0.2 U.
463
+ setUp ( for: . autoBolusIOBClamping, maxBolus: 5 )
464
+
465
+ // This sets up dose rounding
466
+ let delegate = MockDelegate ( )
467
+ loopDataManager. delegate = delegate
468
+
469
+ let updateGroup = DispatchGroup ( )
470
+ updateGroup. enter ( )
471
+
472
+ var insulinOnBoard : InsulinValue ?
473
+ var recommendedBolus : Double ?
474
+ self . loopDataManager. getLoopState { _, state in
475
+ insulinOnBoard = state. insulinOnBoard
476
+ recommendedBolus = state. recommendedAutomaticDose? . recommendation. bolusUnits
477
+ updateGroup. leave ( )
478
+ }
479
+ updateGroup. wait ( )
480
+
481
+ XCTAssertEqual ( recommendedBolus!, 0.5 , accuracy: 0.01 )
482
+ XCTAssertEqual ( insulinOnBoard? . value, 9.47 )
483
+
484
+ /// Set the `maximumBolus` to 10U so there's no clamping
485
+ updateGroup. enter ( )
486
+ self . loopDataManager. mutateSettings { settings in settings. maximumBolus = 10 }
487
+ self . loopDataManager. getLoopState { _, state in
488
+ insulinOnBoard = state. insulinOnBoard
489
+ recommendedBolus = state. recommendedAutomaticDose? . recommendation. bolusUnits
490
+ updateGroup. leave ( )
491
+ }
492
+ updateGroup. wait ( )
493
+
494
+ XCTAssertEqual ( recommendedBolus!, 0.65 , accuracy: 0.01 )
495
+ XCTAssertEqual ( insulinOnBoard? . value, 9.47 )
496
+ }
497
+
498
+ func testTempBasalMaxIOBClamping( ) {
499
+ /// `maximumBolus` is set to 5U to clamp max IOB at 10U
500
+ /// Without clamping: 4.25 U/hr. Clamped recommendation: 1.25 U/hr.
501
+ setUp ( for: . tempBasalIOBClamping, maxBolus: 5 )
502
+
503
+ // This sets up dose rounding
504
+ let delegate = MockDelegate ( )
505
+ loopDataManager. delegate = delegate
506
+
507
+ let updateGroup = DispatchGroup ( )
508
+ updateGroup. enter ( )
509
+
510
+ var insulinOnBoard : InsulinValue ?
511
+ var recommendedBasal : TempBasalRecommendation ?
512
+ self . loopDataManager. getLoopState { _, state in
513
+ insulinOnBoard = state. insulinOnBoard
514
+ recommendedBasal = state. recommendedAutomaticDose? . recommendation. basalAdjustment
515
+ updateGroup. leave ( )
516
+ }
517
+ updateGroup. wait ( )
518
+
519
+ XCTAssertEqual ( recommendedBasal!. unitsPerHour, 1.25 , accuracy: 0.01 )
520
+ XCTAssertEqual ( insulinOnBoard? . value, 9.87 )
521
+
522
+ /// Set the `maximumBolus` to 10U so there's no clamping
523
+ updateGroup. enter ( )
524
+ self . loopDataManager. mutateSettings { settings in settings. maximumBolus = 10 }
525
+ self . loopDataManager. getLoopState { _, state in
526
+ insulinOnBoard = state. insulinOnBoard
527
+ recommendedBasal = state. recommendedAutomaticDose? . recommendation. basalAdjustment
528
+ updateGroup. leave ( )
529
+ }
530
+ updateGroup. wait ( )
531
+
532
+ XCTAssertEqual ( recommendedBasal!. unitsPerHour, 4.25 , accuracy: 0.01 )
533
+ XCTAssertEqual ( insulinOnBoard? . value, 9.87 )
534
+ }
535
+
459
536
}
0 commit comments