diff --git a/app/src/test/java/info/nightscout/androidaps/HardLimitsMock.kt b/app/src/test/java/info/nightscout/androidaps/HardLimitsMock.kt new file mode 100644 index 0000000000..db6fc5800a --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/HardLimitsMock.kt @@ -0,0 +1,84 @@ +package info.nightscout.androidaps + +import info.nightscout.core.main.R +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(R.string.key_age, "")) { + rh.gs(R.string.key_child) -> CHILD + rh.gs(R.string.key_teenage) -> TEENAGE + rh.gs(R.string.key_adult) -> ADULT + rh.gs(R.string.key_resistantadult) -> RESISTANT_ADULT + rh.gs(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 + } +} \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt index 0c80960576..6899bf5912 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.interfaces import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.HardLimitsMock import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.dana.DanaPump @@ -64,8 +65,8 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { @Mock lateinit var insightDatabaseDao: InsightDatabaseDao @Mock lateinit var ruffyScripter: RuffyScripter @Mock lateinit var buildHelper: BuildHelper - @Mock lateinit var hardLimits: HardLimits + private lateinit var hardLimits: HardLimits private lateinit var danaPump: DanaPump private lateinit var insightDbHelper: InsightDbHelper private lateinit var constraintChecker: ConstraintsImpl @@ -130,6 +131,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { val glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculator = iobCobCalculator, dateUtil = dateUtil) + hardLimits = HardLimitsMock(sp, rh) insightDbHelper = InsightDbHelper(insightDatabaseDao) danaPump = DanaPump(aapsLogger, sp, dateUtil, injector) objectivesPlugin = ObjectivesPlugin(injector, aapsLogger, rh, activePlugin, sp, config) diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt index d8b4cc425e..c06d39f562 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.constraints.safety import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.HardLimitsMock import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.interfaces.ActivePlugin @@ -38,8 +39,8 @@ class SafetyPluginTest : TestBaseWithProfile() { @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin @Mock lateinit var glimpPlugin: GlimpPlugin @Mock lateinit var repository: AppRepository - @Mock lateinit var hardLimits: HardLimits + private lateinit var hardLimits: HardLimits private lateinit var safetyPlugin: SafetyPlugin val injector = HasAndroidInjector { AndroidInjector { } } @@ -70,6 +71,7 @@ class SafetyPluginTest : TestBaseWithProfile() { `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) `when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription) `when`(config.APS).thenReturn(true) + hardLimits = HardLimitsMock(sp, rh) safetyPlugin = SafetyPlugin( injector, aapsLogger, rh, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, openAPSSMBDynamicISFPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, diff --git a/core/core-main/src/test/java/info/nightscout/androidaps/HardLimitsMock.kt b/core/core-main/src/test/java/info/nightscout/androidaps/HardLimitsMock.kt new file mode 100644 index 0000000000..db6fc5800a --- /dev/null +++ b/core/core-main/src/test/java/info/nightscout/androidaps/HardLimitsMock.kt @@ -0,0 +1,84 @@ +package info.nightscout.androidaps + +import info.nightscout.core.main.R +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(R.string.key_age, "")) { + rh.gs(R.string.key_child) -> CHILD + rh.gs(R.string.key_teenage) -> TEENAGE + rh.gs(R.string.key_adult) -> ADULT + rh.gs(R.string.key_resistantadult) -> RESISTANT_ADULT + rh.gs(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 + } +} \ No newline at end of file diff --git a/core/core-main/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt b/core/core-main/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt index ce9a00c156..7fba26ef5a 100644 --- a/core/core-main/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt +++ b/core/core-main/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt @@ -21,7 +21,7 @@ import info.nightscout.shared.utils.DateUtil import org.json.JSONObject import org.junit.Before import org.mockito.Mock -import org.mockito.Mockito +import org.mockito.Mockito.`when` @Suppress("SpellCheckingInspection") open class TestBaseWithProfile : TestBase() { @@ -35,8 +35,8 @@ open class TestBaseWithProfile : TestBase() { @Mock lateinit var sp: SP @Mock lateinit var context: Context @Mock lateinit var repository: AppRepository - @Mock lateinit var hardLimits: HardLimits + private lateinit var hardLimits: HardLimits lateinit var testPumpPlugin: TestPumpPlugin val rxBus = RxBus(aapsSchedulers, aapsLogger) @@ -70,7 +70,8 @@ open class TestBaseWithProfile : TestBase() { "\"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) - Mockito.`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin) + `when`(activePluginProvider.activePump).thenReturn(testPumpPlugin) + hardLimits = HardLimitsMock(sp, rh) } fun getValidProfileStore(): ProfileStore { diff --git a/core/core-main/src/test/java/info/nightscout/androidaps/data/ProfileTest.kt b/core/core-main/src/test/java/info/nightscout/androidaps/data/ProfileTest.kt index ef5d3a8899..36dceb7c76 100644 --- a/core/core-main/src/test/java/info/nightscout/androidaps/data/ProfileTest.kt +++ b/core/core-main/src/test/java/info/nightscout/androidaps/data/ProfileTest.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.data import android.content.Context import dagger.android.AndroidInjector +import info.nightscout.androidaps.HardLimitsMock import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.TestPumpPlugin import info.nightscout.androidaps.extensions.pureProfileFromJson @@ -13,7 +14,6 @@ import info.nightscout.core.profile.toMmol import info.nightscout.core.profile.toTargetRangeString import info.nightscout.core.profile.toUnits import info.nightscout.core.profile.toUnitsString -import info.nightscout.database.impl.AppRepository import info.nightscout.interfaces.Config import info.nightscout.interfaces.GlucoseUnit import info.nightscout.interfaces.profile.Profile @@ -43,9 +43,8 @@ class ProfileTest : TestBase() { @Mock lateinit var context: Context @Mock lateinit var config: Config @Mock lateinit var sp: SP - @Mock lateinit var repository: AppRepository - @Mock lateinit var hardLimits: HardLimits + private lateinit var hardLimits: HardLimits private lateinit var rxBus: RxBus private lateinit var dateUtil: DateUtil private lateinit var testPumpPlugin: TestPumpPlugin @@ -70,6 +69,7 @@ class ProfileTest : TestBase() { testPumpPlugin = TestPumpPlugin { AndroidInjector { } } dateUtil = DateUtil(context) rxBus = RxBus(TestAapsSchedulers(), aapsLogger) + hardLimits = HardLimitsMock(sp, rh) `when`(activePluginProvider.activePump).thenReturn(testPumpPlugin) `when`(rh.gs(R.string.profile_per_unit)).thenReturn("/U") `when`(rh.gs(R.string.profile_carbs_per_unit)).thenReturn("g/U")