BolusExtensionKtTest
This commit is contained in:
parent
50818c2d4c
commit
2538378c0c
5 changed files with 262 additions and 0 deletions
|
@ -24,4 +24,6 @@ dependencies {
|
|||
implementation project(':core:utils')
|
||||
implementation project(':core:validators')
|
||||
implementation project(':database:entities')
|
||||
|
||||
testImplementation project(':core:main')
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package info.nightscout.androidaps
|
||||
|
||||
import info.nightscout.interfaces.utils.HardLimits
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class HardLimitsMock @Inject constructor(
|
||||
private val sp: SP,
|
||||
private val rh: ResourceHelper
|
||||
) : HardLimits {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val CHILD = 0
|
||||
private const val TEENAGE = 1
|
||||
private const val ADULT = 2
|
||||
private const val RESISTANT_ADULT = 3
|
||||
private const val PREGNANT = 4
|
||||
private val MAX_BOLUS = doubleArrayOf(5.0, 10.0, 17.0, 25.0, 60.0)
|
||||
|
||||
// Very Hard Limits Ranges
|
||||
// First value is the Lowest and second value is the Highest a Limit can define
|
||||
val VERY_HARD_LIMIT_MIN_BG = doubleArrayOf(80.0, 180.0)
|
||||
val VERY_HARD_LIMIT_MAX_BG = doubleArrayOf(90.0, 200.0)
|
||||
val VERY_HARD_LIMIT_TARGET_BG = doubleArrayOf(80.0, 200.0)
|
||||
|
||||
// Very Hard Limits Ranges for Temp Targets
|
||||
val VERY_HARD_LIMIT_TEMP_MIN_BG = intArrayOf(72, 180)
|
||||
val VERY_HARD_LIMIT_TEMP_MAX_BG = intArrayOf(72, 270)
|
||||
val VERY_HARD_LIMIT_TEMP_TARGET_BG = intArrayOf(72, 200)
|
||||
val MIN_DIA = doubleArrayOf(5.0, 5.0, 5.0, 5.0, 5.0)
|
||||
val MAX_DIA = doubleArrayOf(9.0, 9.0, 9.0, 9.0, 10.0)
|
||||
val MIN_IC = doubleArrayOf(2.0, 2.0, 2.0, 2.0, 0.3)
|
||||
val MAX_IC = doubleArrayOf(100.0, 100.0, 100.0, 100.0, 100.0)
|
||||
const val MIN_ISF = 2.0 // mgdl
|
||||
const val MAX_ISF = 1000.0 // mgdl
|
||||
val MAX_IOB_AMA = doubleArrayOf(3.0, 5.0, 7.0, 12.0, 25.0)
|
||||
val MAX_IOB_SMB = doubleArrayOf(7.0, 13.0, 22.0, 30.0, 70.0)
|
||||
val MAX_BASAL = doubleArrayOf(2.0, 5.0, 10.0, 12.0, 25.0)
|
||||
|
||||
//LGS Hard limits
|
||||
//No IOB at all
|
||||
const val MAX_IOB_LGS = 0.0
|
||||
|
||||
}
|
||||
|
||||
private fun loadAge(): Int = when (sp.getString(info.nightscout.core.utils.R.string.key_age, "")) {
|
||||
rh.gs(info.nightscout.core.utils.R.string.key_child) -> CHILD
|
||||
rh.gs(info.nightscout.core.utils.R.string.key_teenage) -> TEENAGE
|
||||
rh.gs(info.nightscout.core.utils.R.string.key_adult) -> ADULT
|
||||
rh.gs(info.nightscout.core.utils.R.string.key_resistantadult) -> RESISTANT_ADULT
|
||||
rh.gs(info.nightscout.core.utils.R.string.key_pregnant) -> PREGNANT
|
||||
else -> ADULT
|
||||
}
|
||||
|
||||
override fun maxBolus(): Double = MAX_BOLUS[loadAge()]
|
||||
override fun maxIobAMA(): Double = MAX_IOB_AMA[loadAge()]
|
||||
override fun maxIobSMB(): Double = MAX_IOB_SMB[loadAge()]
|
||||
override fun maxBasal(): Double = MAX_BASAL[loadAge()]
|
||||
override fun minDia(): Double = MIN_DIA[loadAge()]
|
||||
override fun maxDia(): Double = MAX_DIA[loadAge()]
|
||||
override fun minIC(): Double = MIN_IC[loadAge()]
|
||||
override fun maxIC(): Double = MAX_IC[loadAge()]
|
||||
|
||||
// safety checks
|
||||
override fun checkHardLimits(value: Double, valueName: Int, lowLimit: Double, highLimit: Double): Boolean =
|
||||
value == verifyHardLimits(value, valueName, lowLimit, highLimit)
|
||||
|
||||
override fun isInRange(value: Double, lowLimit: Double, highLimit: Double): Boolean =
|
||||
value in lowLimit..highLimit
|
||||
|
||||
override fun verifyHardLimits(value: Double, valueName: Int, lowLimit: Double, highLimit: Double): Double {
|
||||
var newValue = value
|
||||
if (newValue < lowLimit || newValue > highLimit) {
|
||||
newValue = max(newValue, lowLimit)
|
||||
newValue = min(newValue, highLimit)
|
||||
}
|
||||
return newValue
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package info.nightscout.androidaps
|
||||
|
||||
import android.content.Context
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.core.extensions.pureProfileFromJson
|
||||
import info.nightscout.core.profile.ProfileSealed
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.profile.DefaultValueHelper
|
||||
import info.nightscout.interfaces.profile.Profile
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.utils.HardLimits
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import org.json.JSONObject
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
open class TestBaseWithProfile : TestBase() {
|
||||
|
||||
@Mock lateinit var activePluginProvider: ActivePlugin
|
||||
@Mock lateinit var rh: ResourceHelper
|
||||
@Mock lateinit var profileFunction: ProfileFunction
|
||||
@Mock lateinit var defaultValueHelper: DefaultValueHelper
|
||||
@Mock lateinit var dateUtil: DateUtil
|
||||
@Mock lateinit var config: Config
|
||||
@Mock lateinit var sp: SP
|
||||
@Mock lateinit var context: Context
|
||||
|
||||
lateinit var hardLimits: HardLimits
|
||||
lateinit var testPumpPlugin: TestPumpPlugin
|
||||
|
||||
val rxBus = RxBus(aapsSchedulers, aapsLogger)
|
||||
|
||||
val profileInjector = HasAndroidInjector { AndroidInjector { } }
|
||||
|
||||
private lateinit var invalidProfileJSON: String
|
||||
private lateinit var validProfileJSON: String
|
||||
lateinit var validProfile: Profile
|
||||
lateinit var invalidProfile: Profile
|
||||
@Suppress("PropertyName") val TESTPROFILENAME = "someProfile"
|
||||
|
||||
@BeforeEach
|
||||
fun prepareMock() {
|
||||
invalidProfileJSON = "{\"dia\":\"1\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," +
|
||||
"{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," +
|
||||
"\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
||||
validProfileJSON = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," +
|
||||
"{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," +
|
||||
"\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
||||
validProfile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(validProfileJSON), dateUtil)!!)
|
||||
testPumpPlugin = TestPumpPlugin(profileInjector)
|
||||
`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin)
|
||||
hardLimits = HardLimitsMock(sp, rh)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package info.nightscout.androidaps
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.interfaces.profile.Profile
|
||||
import info.nightscout.interfaces.pump.DetailedBolusInfo
|
||||
import info.nightscout.interfaces.pump.Pump
|
||||
import info.nightscout.interfaces.pump.PumpEnactResult
|
||||
import info.nightscout.interfaces.pump.PumpSync
|
||||
import info.nightscout.interfaces.pump.defs.ManufacturerType
|
||||
import info.nightscout.interfaces.pump.defs.PumpDescription
|
||||
import info.nightscout.interfaces.pump.defs.PumpType
|
||||
import info.nightscout.interfaces.utils.TimeChangeType
|
||||
import org.json.JSONObject
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class TestPumpPlugin(val injector: HasAndroidInjector) : Pump {
|
||||
|
||||
var connected = false
|
||||
var isProfileSet = true
|
||||
|
||||
override fun isConnected() = connected
|
||||
override fun isConnecting() = false
|
||||
override fun isHandshakeInProgress() = false
|
||||
val lastData = 0L
|
||||
|
||||
val baseBasal = 0.0
|
||||
override var pumpDescription = PumpDescription()
|
||||
|
||||
override fun isInitialized(): Boolean = true
|
||||
override fun isSuspended(): Boolean = false
|
||||
override fun isBusy(): Boolean = false
|
||||
override fun connect(reason: String) {
|
||||
connected = true
|
||||
}
|
||||
|
||||
override fun disconnect(reason: String) {
|
||||
connected = false
|
||||
}
|
||||
|
||||
override fun stopConnecting() {
|
||||
connected = false
|
||||
}
|
||||
|
||||
override fun waitForDisconnectionInSeconds(): Int = 0
|
||||
override fun getPumpStatus(reason: String) {}
|
||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult = PumpEnactResult(injector)
|
||||
override fun isThisProfileSet(profile: Profile): Boolean = isProfileSet
|
||||
override fun lastDataTime(): Long = lastData
|
||||
override val baseBasalRate: Double = baseBasal
|
||||
override val reservoirLevel: Double = 0.0
|
||||
override val batteryLevel: Int = 0
|
||||
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult = PumpEnactResult(injector).success(true)
|
||||
override fun stopBolusDelivering() {}
|
||||
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult =
|
||||
PumpEnactResult(injector).success(true)
|
||||
|
||||
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult =
|
||||
PumpEnactResult(injector).success(true)
|
||||
|
||||
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult = PumpEnactResult(injector).success(true)
|
||||
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true)
|
||||
override fun cancelExtendedBolus(): PumpEnactResult = PumpEnactResult(injector).success(true)
|
||||
override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject = JSONObject()
|
||||
override fun manufacturer(): ManufacturerType = ManufacturerType.AAPS
|
||||
override fun model(): PumpType = PumpType.GENERIC_AAPS
|
||||
override fun serialNumber(): String = "1"
|
||||
override fun shortStatus(veryShort: Boolean): String = ""
|
||||
override val isFakingTempsByExtendedBoluses: Boolean = false
|
||||
override fun loadTDDs(): PumpEnactResult = PumpEnactResult(injector).success(true)
|
||||
override fun canHandleDST(): Boolean = true
|
||||
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package info.nightscout.core.extensions
|
||||
|
||||
import info.nightscout.androidaps.TestBaseWithProfile
|
||||
import info.nightscout.database.entities.Bolus
|
||||
import info.nightscout.insulin.InsulinLyumjevPlugin
|
||||
import info.nightscout.interfaces.insulin.Insulin
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.ui.UiInteraction
|
||||
import info.nightscout.shared.utils.T
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
|
||||
class BolusExtensionKtTest : TestBaseWithProfile() {
|
||||
|
||||
@Mock lateinit var activePlugin: ActivePlugin
|
||||
@Mock lateinit var profileFunctions: ProfileFunction
|
||||
@Mock lateinit var uiInteraction: UiInteraction
|
||||
|
||||
private lateinit var insulin: Insulin
|
||||
|
||||
private val now = 1000000L
|
||||
private val dia = 7.0
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
insulin = InsulinLyumjevPlugin(profileInjector, rh, profileFunctions, rxBus, aapsLogger, config, hardLimits, uiInteraction)
|
||||
Mockito.`when`(activePlugin.activeInsulin).thenReturn(insulin)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun iobCalc() {
|
||||
val bolus = Bolus(timestamp = now - 1, amount = 1.0, type = Bolus.Type.NORMAL)
|
||||
// there should be almost full IOB after now
|
||||
Assertions.assertEquals(1.0, bolus.iobCalc(activePlugin, now, dia).iobContrib, 0.01)
|
||||
// there should be less that 5% after DIA -1
|
||||
Assertions.assertTrue(0.05 > bolus.iobCalc(activePlugin, now + T.hours(dia.toLong() - 1).msecs(), dia).iobContrib)
|
||||
// there should be zero after DIA
|
||||
Assertions.assertEquals(0.0, bolus.iobCalc(activePlugin, now + T.hours(dia.toLong() + 1).msecs(), dia).iobContrib)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue