From acf9f05928cbf808ed9c3ed986c02dd9973a57bb Mon Sep 17 00:00:00 2001 From: AdrianLxM Date: Wed, 29 Apr 2020 00:39:20 +0200 Subject: [PATCH 01/12] Removed internal function TypedArrayUtils is marked as `@RestrictTo(LIBRARY_GROUP_PREFIX)`. getAttr() will chose between the two parameters, so if both are the same has no functionality anyway. --- .../utils/textValidator/ValidatingEditTextPreference.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/textValidator/ValidatingEditTextPreference.kt b/app/src/main/java/info/nightscout/androidaps/utils/textValidator/ValidatingEditTextPreference.kt index 190a3bea73..b4a49c42de 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/textValidator/ValidatingEditTextPreference.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/textValidator/ValidatingEditTextPreference.kt @@ -2,7 +2,6 @@ package info.nightscout.androidaps.utils.textValidator import android.content.Context import android.util.AttributeSet -import androidx.core.content.res.TypedArrayUtils import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference.OnBindEditTextListener import androidx.preference.PreferenceViewHolder @@ -23,8 +22,7 @@ class ValidatingEditTextPreference(ctx: Context, attrs: AttributeSet, defStyleAt : this(ctx, attrs, defStyle, 0) constructor(ctx: Context, attrs: AttributeSet) - : this(ctx, attrs, TypedArrayUtils.getAttr(ctx, R.attr.editTextPreferenceStyle, - R.attr.editTextPreferenceStyle)) + : this(ctx, attrs, R.attr.editTextPreferenceStyle) private lateinit var editTextValidator: EditTextValidator @@ -33,4 +31,4 @@ class ValidatingEditTextPreference(ctx: Context, attrs: AttributeSet, defStyleAt holder?.isDividerAllowedAbove = false holder?.isDividerAllowedBelow = false } -} \ No newline at end of file +} From 01e8934f7a9b9009d2155b43213d277eedb72d59 Mon Sep 17 00:00:00 2001 From: Tim Gunn <2896311+Tornado-Tim@users.noreply.github.com> Date: Sat, 2 May 2020 00:05:50 +1200 Subject: [PATCH 02/12] Add deterministic LGS function --- .../androidaps/plugins/aps/loop/LoopPlugin.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java index fefd50f132..dcf32753a1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java @@ -288,6 +288,21 @@ public class LoopPlugin extends PluginBase { return true; } + public boolean isLGS(){ + Constraint closedLoopEnabled = constraintChecker.isClosedLoopAllowed(); + Double MaxIOBallowed = constraintChecker.getMaxIOBAllowed().value(); + String APSmode = sp.getString(R.string.key_aps_mode, "open"); + Double LGSthreshold = 0d; + PumpInterface pump = activePlugin.getActivePump(); + boolean isLGS = false; + if (!isSuspended() && !pump.isSuspended()) + if (closedLoopEnabled.value()) + if ((MaxIOBallowed.equals(LGSthreshold)) || (APSmode.equals("lgs"))) + isLGS = true; + + return isLGS; + } + public boolean isSuperBolus() { if (loopSuspendedTill == 0) return false; From b54e1a0af365bcbe3ab37530634d70ba656c2f8d Mon Sep 17 00:00:00 2001 From: Tim Gunn <2896311+Tornado-Tim@users.noreply.github.com> Date: Sat, 2 May 2020 00:07:24 +1200 Subject: [PATCH 03/12] Add LGS --- .../plugins/constraints/safety/SafetyPlugin.java | 6 +++++- .../plugins/general/overview/OverviewFragment.kt | 6 ++++-- .../java/info/nightscout/androidaps/utils/HardLimits.kt | 8 ++++++++ app/src/main/res/values/arrays.xml | 2 ++ app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 2 ++ 6 files changed, 22 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java index a32b7233e1..dbb2b650ed 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java @@ -98,7 +98,7 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface { @NonNull @Override public Constraint isClosedLoopAllowed(@NonNull Constraint value) { String mode = sp.getString(R.string.key_aps_mode, "open"); - if (!mode.equals("closed")) + if ((mode.equals("open"))) value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.closedmodedisabledinpreferences), this); if (!buildHelper.isEngineeringModeOrRelease()) { @@ -266,6 +266,7 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface { @NonNull @Override public Constraint applyMaxIOBConstraints(@NonNull Constraint maxIob) { double maxIobPref; + String apsmode = sp.getString(R.string.key_aps_mode, "open"); if (openAPSSMBPlugin.isEnabled(PluginType.APS)) maxIobPref = sp.getDouble(R.string.key_openapssmb_max_iob, 3d); else @@ -276,6 +277,9 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface { maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobAMA(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobAMA(), getResourceHelper().gs(R.string.hardlimit)), this); if (openAPSSMBPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobSMB(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobSMB(), getResourceHelper().gs(R.string.hardlimit)), this); + if ((apsmode.equals("lgs"))) + maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobLGS(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobLGS(), getResourceHelper().gs(R.string.lowglucosesuspend)), this); + return maxIob; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt index cc3f881a13..fc1b80bd2a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt @@ -622,8 +622,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } loopPlugin.isEnabled(PluginType.LOOP) -> { - overview_apsmode?.text = if (closedLoopEnabled.value()) resourceHelper.gs(R.string.closedloop) else resourceHelper.gs(R.string.openloop) - overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault)) + val APSmode = sp.getString(R.string.key_aps_mode, "open") + val isLGS = loopPlugin.isLGS + overview_apsmode?.text = if (closedLoopEnabled.value()) if (isLGS) resourceHelper.gs(R.string.lgs) else resourceHelper.gs(R.string.closedloop) else resourceHelper.gs(R.string.openloop) + overview_apsmode?.setBackgroundColor(if (isLGS) resourceHelper.gc(R.color.ribbonUnusual) else resourceHelper.gc(R.color.ribbonDefault)) overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault)) } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt b/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt index 48eba49112..5943da70a4 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt @@ -45,6 +45,10 @@ class HardLimits @Inject constructor( val MAXIOB_SMB = doubleArrayOf(3.0, 7.0, 12.0, 25.0) val MAXBASAL = doubleArrayOf(2.0, 5.0, 10.0, 12.0) + //LGS Hard limits + //No IOB at all + val MAXIOB_LGS = 0.0 + private fun loadAge(): Int { val sp_age = sp.getString(R.string.key_age, "") val age: Int @@ -68,6 +72,10 @@ class HardLimits @Inject constructor( return MAXIOB_SMB[loadAge()] } + fun maxIobLGS(): Double { + return MAXIOB_LGS + } + fun maxBasal(): Double { return MAXBASAL[loadAge()] } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 04d78d3406..d11a14eefd 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -4,10 +4,12 @@ @string/closedloop @string/openloop + @string/lowglucosesuspend closed open + lgs diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 8d1b977fea..d30a19a76e 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -86,6 +86,7 @@ #ff0400 #FFFFFF #303030 + #01017A #FFFFFF #2E2E2E diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b0f6821b69..45ed657b64 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -187,10 +187,12 @@ Closed Loop Open Loop + Low Glucose Suspend Loop Disabled Disable loop Enable loop + LGS New suggestion available Unsupported version of Nightscout LOOP DISABLED BY CONSTRAINTS From 560a081c7c3b5c0006ba078de7b2cc7437ba0bea Mon Sep 17 00:00:00 2001 From: Tim Gunn <2896311+Tornado-Tim@users.noreply.github.com> Date: Sat, 2 May 2020 01:50:35 +1200 Subject: [PATCH 04/12] Inherit from HardLimits class --- .../androidaps/plugins/aps/loop/LoopPlugin.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java index dcf32753a1..93fcef0f0b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java @@ -68,6 +68,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.T; import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.sharedPreferences.SP; +import info.nightscout.androidaps.utils.HardLimits; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; @@ -88,6 +89,7 @@ public class LoopPlugin extends PluginBase { private final IobCobCalculatorPlugin iobCobCalculatorPlugin; private final ReceiverStatusStore receiverStatusStore; private final FabricPrivacy fabricPrivacy; + private final HardLimits hardLimits; private CompositeDisposable disposable = new CompositeDisposable(); @@ -132,7 +134,8 @@ public class LoopPlugin extends PluginBase { Lazy actionStringHandler, // TODO Adrian use RxBus instead of Lazy IobCobCalculatorPlugin iobCobCalculatorPlugin, ReceiverStatusStore receiverStatusStore, - FabricPrivacy fabricPrivacy + FabricPrivacy fabricPrivacy, + HardLimits hardLimits ) { super(new PluginDescription() .mainType(PluginType.LOOP) @@ -158,6 +161,7 @@ public class LoopPlugin extends PluginBase { this.iobCobCalculatorPlugin = iobCobCalculatorPlugin; this.receiverStatusStore = receiverStatusStore; this.fabricPrivacy = fabricPrivacy; + this.hardLimits = hardLimits; loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L); isSuperBolus = sp.getBoolean("isSuperBolus", false); @@ -292,12 +296,12 @@ public class LoopPlugin extends PluginBase { Constraint closedLoopEnabled = constraintChecker.isClosedLoopAllowed(); Double MaxIOBallowed = constraintChecker.getMaxIOBAllowed().value(); String APSmode = sp.getString(R.string.key_aps_mode, "open"); - Double LGSthreshold = 0d; PumpInterface pump = activePlugin.getActivePump(); boolean isLGS = false; + if (!isSuspended() && !pump.isSuspended()) if (closedLoopEnabled.value()) - if ((MaxIOBallowed.equals(LGSthreshold)) || (APSmode.equals("lgs"))) + if ((MaxIOBallowed.equals(hardLimits.getMAXIOB_LGS())) || (APSmode.equals("lgs"))) isLGS = true; return isLGS; From 96757145bf039a2a9d8a147f18c78a296358918d Mon Sep 17 00:00:00 2001 From: Tim Gunn <2896311+Tornado-Tim@users.noreply.github.com> Date: Sat, 2 May 2020 01:54:08 +1200 Subject: [PATCH 05/12] Use auto getter method --- .../androidaps/plugins/constraints/safety/SafetyPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java index dbb2b650ed..ab325f1f0c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java @@ -278,7 +278,7 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface { if (openAPSSMBPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobSMB(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobSMB(), getResourceHelper().gs(R.string.hardlimit)), this); if ((apsmode.equals("lgs"))) - maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobLGS(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobLGS(), getResourceHelper().gs(R.string.lowglucosesuspend)), this); + maxIob.setIfSmaller(getAapsLogger(), hardLimits.getMAXIOB_LGS(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.getMAXIOB_LGS(), getResourceHelper().gs(R.string.lowglucosesuspend)), this); return maxIob; } From 9e2c3255e2568b3198d53542d46841191f494574 Mon Sep 17 00:00:00 2001 From: Tim Gunn <2896311+Tornado-Tim@users.noreply.github.com> Date: Sat, 2 May 2020 01:54:46 +1200 Subject: [PATCH 06/12] Remove not needed getter function --- .../main/java/info/nightscout/androidaps/utils/HardLimits.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt b/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt index 5943da70a4..c9e2835ceb 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt @@ -72,10 +72,6 @@ class HardLimits @Inject constructor( return MAXIOB_SMB[loadAge()] } - fun maxIobLGS(): Double { - return MAXIOB_LGS - } - fun maxBasal(): Double { return MAXBASAL[loadAge()] } From 5c3876217813d76f4651ef74cf42227043274a34 Mon Sep 17 00:00:00 2001 From: Tim Gunn <2896311+Tornado-Tim@users.noreply.github.com> Date: Sat, 2 May 2020 01:55:11 +1200 Subject: [PATCH 07/12] Format code so its easier to read --- .../plugins/general/overview/OverviewFragment.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt index fc1b80bd2a..962e443c66 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt @@ -622,9 +622,16 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } loopPlugin.isEnabled(PluginType.LOOP) -> { - val APSmode = sp.getString(R.string.key_aps_mode, "open") val isLGS = loopPlugin.isLGS - overview_apsmode?.text = if (closedLoopEnabled.value()) if (isLGS) resourceHelper.gs(R.string.lgs) else resourceHelper.gs(R.string.closedloop) else resourceHelper.gs(R.string.openloop) + overview_apsmode?.text = + if (closedLoopEnabled.value()) + if (isLGS) + resourceHelper.gs(R.string.lgs) + else + resourceHelper.gs(R.string.closedloop) + else + resourceHelper.gs(R.string.openloop) + overview_apsmode?.setBackgroundColor(if (isLGS) resourceHelper.gc(R.color.ribbonUnusual) else resourceHelper.gc(R.color.ribbonDefault)) overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault)) } From 0bbdca3b4adf67a59145a98b9959c53abf6ed2c8 Mon Sep 17 00:00:00 2001 From: Tim Gunn <2896311+Tornado-Tim@users.noreply.github.com> Date: Sat, 2 May 2020 14:50:53 +1200 Subject: [PATCH 08/12] Add test --- .../plugins/constraints/safety/SafetyPluginTest.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 9da162a301..28261260a9 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 @@ -242,4 +242,14 @@ class SafetyPluginTest : TestBaseWithProfile() { """.trimIndent(), d.getReasons(aapsLogger)) Assert.assertEquals("Safety: Limiting IOB to 1.5 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger)) } + + @Test fun iobShouldBeZero() { + `when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("lgs") + + // Apply IOB limits + var d = Constraint(hardLimits.MAXIOB_LGS) + d = safetyPlugin.applyMaxIOBConstraints(d) + Assert.assertEquals(0.0, d.value()!!) + Assert.assertEquals("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend", d.getMostLimitedReasons(aapsLogger)) + } } \ No newline at end of file From 4c2fdef71abb5c10315322ed44f699f1a34e6070 Mon Sep 17 00:00:00 2001 From: Tim Gunn <2896311+Tornado-Tim@users.noreply.github.com> Date: Sat, 2 May 2020 19:13:16 +1200 Subject: [PATCH 09/12] Fix tests --- .../androidaps/plugins/aps/loop/LoopPluginTest.kt | 8 +++++++- .../plugins/constraints/safety/SafetyPluginTest.kt | 11 +---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt index dbfa209d11..40495880a3 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt @@ -19,6 +19,7 @@ import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Assert @@ -49,11 +50,15 @@ class LoopPluginTest : TestBase() { @Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var receiverStatusStore: ReceiverStatusStore + private lateinit var hardLimits: HardLimits + lateinit var loopPlugin: LoopPlugin val injector = HasAndroidInjector { AndroidInjector { } } @Before fun prepareMock() { - loopPlugin = LoopPlugin(injector, aapsLogger, rxBus, sp, constraintChecker, resourceHelper, profileFunction, context, commandQueue, activePlugin, treatmentsPlugin, virtualPumpPlugin, actionStringHandler, iobCobCalculatorPlugin, receiverStatusStore, fabricPrivacy) + hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context) + + loopPlugin = LoopPlugin(injector, aapsLogger, rxBus, sp, constraintChecker, resourceHelper, profileFunction, context, commandQueue, activePlugin, treatmentsPlugin, virtualPumpPlugin, actionStringHandler, iobCobCalculatorPlugin, receiverStatusStore, fabricPrivacy, hardLimits) `when`(activePlugin.getActivePump()).thenReturn(virtualPumpPlugin) } @@ -61,6 +66,7 @@ class LoopPluginTest : TestBase() { fun testPluginInterface() { `when`(resourceHelper.gs(R.string.loop)).thenReturn("Loop") `when`(resourceHelper.gs(R.string.loop_shortname)).thenReturn("LOOP") + `when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("closed") val pumpDescription = PumpDescription() `when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription) Assert.assertEquals(LoopFragment::class.java.name, loopPlugin.pluginDescription.fragmentClass) 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 28261260a9..3e36b8bca0 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 @@ -230,6 +230,7 @@ class SafetyPluginTest : TestBaseWithProfile() { } @Test fun iobShouldBeLimited() { + `when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("closed") `when`(sp.getDouble(R.string.key_openapsma_max_iob, 1.5)).thenReturn(1.5) `when`(sp.getString(R.string.key_age, "")).thenReturn("teenage") @@ -242,14 +243,4 @@ class SafetyPluginTest : TestBaseWithProfile() { """.trimIndent(), d.getReasons(aapsLogger)) Assert.assertEquals("Safety: Limiting IOB to 1.5 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger)) } - - @Test fun iobShouldBeZero() { - `when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("lgs") - - // Apply IOB limits - var d = Constraint(hardLimits.MAXIOB_LGS) - d = safetyPlugin.applyMaxIOBConstraints(d) - Assert.assertEquals(0.0, d.value()!!) - Assert.assertEquals("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend", d.getMostLimitedReasons(aapsLogger)) - } } \ No newline at end of file From 9efbbd3c1715fa1984d8fe7e71c4b105c29b30c4 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sat, 2 May 2020 10:49:55 +0200 Subject: [PATCH 10/12] clanup --- .../general/overview/StatusLightHandler.kt | 18 +++--- .../maintenance/ClassicPrefsFormatTest.kt | 24 ++++---- .../maintenance/EncryptedPrefsFormatTest.kt | 35 ++++++------ .../testing/mockers/AAPSMocker.java | 56 ------------------- .../testing/utils/SingleStringStorage.kt | 12 +--- 5 files changed, 42 insertions(+), 103 deletions(-) delete mode 100644 app/src/test/java/info/nightscout/androidaps/testing/mockers/AAPSMocker.java diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt index 54bb6f3177..b05e1cb015 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt @@ -28,17 +28,17 @@ class StatusLightHandler @Inject constructor( */ fun updateStatusLights(careportal_canulaage: TextView?, careportal_insulinage: TextView?, careportal_reservoirlevel: TextView?, careportal_sensorage: TextView?, careportal_pbage: TextView?, careportal_batterylevel: TextView?) { val pump = activePlugin.activePump - handleAge(careportal_canulaage, "cage", CareportalEvent.SITECHANGE, R.string.key_statuslights_cage_warning, 48.0, R.string.key_statuslights_cage_critical, 72.0) - handleAge(careportal_insulinage, "iage", CareportalEvent.INSULINCHANGE, R.string.key_statuslights_iage_warning, 72.0, R.string.key_statuslights_iage_critical, 144.0) - handleAge(careportal_sensorage, "sage", CareportalEvent.SENSORCHANGE, R.string.key_statuslights_sage_warning, 216.0, R.string.key_statuslights_sage_critical, 240.0) - handleAge(careportal_pbage, "bage", CareportalEvent.PUMPBATTERYCHANGE, R.string.key_statuslights_bage_warning, 216.0, R.string.key_statuslights_bage_critical, 240.0) + handleAge(careportal_canulaage, CareportalEvent.SITECHANGE, R.string.key_statuslights_cage_warning, 48.0, R.string.key_statuslights_cage_critical, 72.0) + handleAge(careportal_insulinage, CareportalEvent.INSULINCHANGE, R.string.key_statuslights_iage_warning, 72.0, R.string.key_statuslights_iage_critical, 144.0) + handleAge(careportal_sensorage, CareportalEvent.SENSORCHANGE, R.string.key_statuslights_sage_warning, 216.0, R.string.key_statuslights_sage_critical, 240.0) + handleAge(careportal_pbage, CareportalEvent.PUMPBATTERYCHANGE, R.string.key_statuslights_bage_warning, 216.0, R.string.key_statuslights_bage_critical, 240.0) if (!Config.NSCLIENT) - handleLevel(careportal_reservoirlevel, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel) + handleLevel(careportal_reservoirlevel, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, "U") if (!Config.NSCLIENT && pump.model() != PumpType.AccuChekCombo) - handleLevel(careportal_batterylevel, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble()) + handleLevel(careportal_batterylevel, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%") } - private fun handleAge(view: TextView?, nsSettingPlugin: String, eventName: String, @StringRes warnSettings: Int, defaultWarnThreshold: Double, @StringRes urgentSettings: Int, defaultUrgentThreshold: Double) { + private fun handleAge(view: TextView?, eventName: String, @StringRes warnSettings: Int, defaultWarnThreshold: Double, @StringRes urgentSettings: Int, defaultUrgentThreshold: Double) { val warn = sp.getDouble(warnSettings, defaultWarnThreshold) val urgent = sp.getDouble(urgentSettings, defaultUrgentThreshold) val careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(eventName) @@ -50,11 +50,11 @@ class StatusLightHandler @Inject constructor( } } - private fun handleLevel(view: TextView?, criticalSetting: Int, criticalDefaultValue: Double, warnSetting: Int, warnDefaultValue: Double, level: Double) { + private fun handleLevel(view: TextView?, criticalSetting: Int, criticalDefaultValue: Double, warnSetting: Int, warnDefaultValue: Double, level: Double, units: String) { val resUrgent = sp.getDouble(criticalSetting, criticalDefaultValue) val resWarn = sp.getDouble(warnSetting, warnDefaultValue) @Suppress("SetTextI18n") - view?.text = " " + DecimalFormatter.to0Decimal(level) + view?.text = " " + DecimalFormatter.to0Decimal(level) + units warnColors.setColorInverse(view, level, resWarn, resUrgent) } } \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/ClassicPrefsFormatTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/ClassicPrefsFormatTest.kt index 0755190d2b..f0a5c07491 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/ClassicPrefsFormatTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/ClassicPrefsFormatTest.kt @@ -1,45 +1,36 @@ package info.nightscout.androidaps.plugins.general.maintenance -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.plugins.general.maintenance.formats.ClassicPrefsFormat import info.nightscout.androidaps.plugins.general.maintenance.formats.Prefs -import info.nightscout.androidaps.testing.mockers.AAPSMocker import info.nightscout.androidaps.testing.utils.SingleStringStorage import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.hamcrest.CoreMatchers import org.junit.Assert -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.`when` import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner import java.io.File @RunWith(PowerMockRunner::class) -@PrepareForTest(AAPSMocker::class, MainApp::class, File::class) +@PrepareForTest(File::class) class ClassicPrefsFormatTest : TestBase() { @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var sp: SP - @Before - fun mock() { - AAPSMocker.prepareMock() - AAPSMocker.resetMockedSharedPrefs() - } - @Test fun preferenceLoadingTest() { val test = "key1::val1\nkeyB::valB" val classicFormat = ClassicPrefsFormat(resourceHelper, SingleStringStorage(test)) - val prefs = classicFormat.loadPreferences(AAPSMocker.getMockedFile(), "") + val prefs = classicFormat.loadPreferences(getMockedFile(), "") Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2)) Assert.assertThat(prefs.values["key1"], CoreMatchers.`is`("val1")) @@ -59,7 +50,14 @@ class ClassicPrefsFormatTest : TestBase() { mapOf() ) - classicFormat.savePreferences(AAPSMocker.getMockedFile(), prefs) + classicFormat.savePreferences(getMockedFile(), prefs) } + private fun getMockedFile(): File { + val file = Mockito.mock(File::class.java) + `when`(file.exists()).thenReturn(true) + `when`(file.canRead()).thenReturn(true) + `when`(file.canWrite()).thenReturn(true) + return file + } } diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/EncryptedPrefsFormatTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/EncryptedPrefsFormatTest.kt index 4537783ce4..fa52651e50 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/EncryptedPrefsFormatTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/EncryptedPrefsFormatTest.kt @@ -1,9 +1,7 @@ package info.nightscout.androidaps.plugins.general.maintenance -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.plugins.general.maintenance.formats.* -import info.nightscout.androidaps.testing.mockers.AAPSMocker import info.nightscout.androidaps.testing.utils.SingleStringStorage import info.nightscout.androidaps.utils.CryptoUtil import info.nightscout.androidaps.utils.assumeAES256isSupported @@ -24,19 +22,17 @@ import java.io.File @PowerMockIgnore("javax.crypto.*") @RunWith(PowerMockRunner::class) -@PrepareForTest(AAPSMocker::class, MainApp::class, File::class, ResourceHelper::class) +@PrepareForTest(File::class) class EncryptedPrefsFormatTest : TestBase() { @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var sp: SP - var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger) + private var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger) @Before fun mock() { - AAPSMocker.prepareMock() - AAPSMocker.resetMockedSharedPrefs() Mockito.`when`(resourceHelper.gs(ArgumentMatchers.anyInt())).thenReturn("mock translation") } @@ -56,7 +52,7 @@ class EncryptedPrefsFormatTest : TestBase() { val storage = SingleStringStorage(frozenPrefs) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) - val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") + val prefs = encryptedFormat.loadPreferences(getMockedFile(), "sikret") assumeAES256isSupported(cryptoUtil) @@ -82,7 +78,7 @@ class EncryptedPrefsFormatTest : TestBase() { PrefsMetadataKey.ENCRYPTION to PrefMetadata(EncryptedPrefsFormat.FORMAT_KEY_ENC, PrefsStatus.OK) ) ) - encryptedFormat.savePreferences(AAPSMocker.getMockedFile(), prefs, "sikret") + encryptedFormat.savePreferences(getMockedFile(), prefs, "sikret") aapsLogger.debug(storage.contents) } @@ -99,8 +95,8 @@ class EncryptedPrefsFormatTest : TestBase() { PrefsMetadataKey.ENCRYPTION to PrefMetadata(EncryptedPrefsFormat.FORMAT_KEY_ENC, PrefsStatus.OK) ) ) - encryptedFormat.savePreferences(AAPSMocker.getMockedFile(), prefsIn, "tajemnica") - val prefsOut = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "tajemnica") + encryptedFormat.savePreferences(getMockedFile(), prefsIn, "tajemnica") + val prefsOut = encryptedFormat.loadPreferences(getMockedFile(), "tajemnica") assumeAES256isSupported(cryptoUtil) @@ -129,7 +125,7 @@ class EncryptedPrefsFormatTest : TestBase() { val storage = SingleStringStorage(frozenPrefs) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) - val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "it-is-NOT-right-secret") + val prefs = encryptedFormat.loadPreferences(getMockedFile(), "it-is-NOT-right-secret") Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0)) @@ -156,7 +152,7 @@ class EncryptedPrefsFormatTest : TestBase() { val storage = SingleStringStorage(frozenPrefs) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) - val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") + val prefs = encryptedFormat.loadPreferences(getMockedFile(), "sikret") assumeAES256isSupported(cryptoUtil) @@ -183,7 +179,7 @@ class EncryptedPrefsFormatTest : TestBase() { val storage = SingleStringStorage(frozenPrefs) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) - val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") + val prefs = encryptedFormat.loadPreferences(getMockedFile(), "sikret") Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0)) Assert.assertThat(prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status, CoreMatchers.`is`(PrefsStatus.ERROR)) @@ -198,7 +194,7 @@ class EncryptedPrefsFormatTest : TestBase() { val storage = SingleStringStorage(frozenPrefs) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) - val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") + val prefs = encryptedFormat.loadPreferences(getMockedFile(), "sikret") Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0)) Assert.assertThat(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.status, CoreMatchers.`is`(PrefsStatus.ERROR)) @@ -210,7 +206,7 @@ class EncryptedPrefsFormatTest : TestBase() { val storage = SingleStringStorage(frozenPrefs) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) - encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") + encryptedFormat.loadPreferences(getMockedFile(), "sikret") } @Test(expected = PrefFormatError::class) @@ -229,7 +225,14 @@ class EncryptedPrefsFormatTest : TestBase() { val storage = SingleStringStorage(frozenPrefs) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) - encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") + encryptedFormat.loadPreferences(getMockedFile(), "sikret") } + private fun getMockedFile(): File { + val file = Mockito.mock(File::class.java) + Mockito.`when`(file.exists()).thenReturn(true) + Mockito.`when`(file.canRead()).thenReturn(true) + Mockito.`when`(file.canWrite()).thenReturn(true) + return file + } } diff --git a/app/src/test/java/info/nightscout/androidaps/testing/mockers/AAPSMocker.java b/app/src/test/java/info/nightscout/androidaps/testing/mockers/AAPSMocker.java deleted file mode 100644 index 3b495af147..0000000000 --- a/app/src/test/java/info/nightscout/androidaps/testing/mockers/AAPSMocker.java +++ /dev/null @@ -1,56 +0,0 @@ -package info.nightscout.androidaps.testing.mockers; - -import android.content.Context; -import android.content.SharedPreferences; - -import org.mockito.ArgumentMatchers; -import org.mockito.invocation.InvocationOnMock; -import org.powermock.api.mockito.PowerMockito; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; - -import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.testing.mocks.SharedPreferencesMock; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.mockStatic; - -public class AAPSMocker { - - private static final Map mockedSharedPrefs = new HashMap<>(); - - public static void prepareMock() throws Exception { - Context mockedContext = mock(Context.class); - mockStatic(MainApp.class, InvocationOnMock::callRealMethod); - - PowerMockito.when(mockedContext, "getSharedPreferences", ArgumentMatchers.anyString(), ArgumentMatchers.anyInt()).thenAnswer(invocation -> { - - final String key = invocation.getArgument(0); - if (mockedSharedPrefs.containsKey(key)) { - return mockedSharedPrefs.get(key); - } else { - SharedPreferencesMock newPrefs = new SharedPreferencesMock(); - mockedSharedPrefs.put(key, newPrefs); - return newPrefs; - } - }); - - resetMockedSharedPrefs(); - } - - public static void resetMockedSharedPrefs() { - mockedSharedPrefs.clear(); - } - - public static File getMockedFile() { - File file = mock(File.class); - when(file.exists()).thenReturn(true); - when(file.canRead()).thenReturn(true); - when(file.canWrite()).thenReturn(true); - return file; - } - -} diff --git a/app/src/test/java/info/nightscout/androidaps/testing/utils/SingleStringStorage.kt b/app/src/test/java/info/nightscout/androidaps/testing/utils/SingleStringStorage.kt index 8a3b06d56e..9991779066 100644 --- a/app/src/test/java/info/nightscout/androidaps/testing/utils/SingleStringStorage.kt +++ b/app/src/test/java/info/nightscout/androidaps/testing/utils/SingleStringStorage.kt @@ -3,20 +3,14 @@ package info.nightscout.androidaps.testing.utils import info.nightscout.androidaps.utils.storage.Storage import java.io.File -class SingleStringStorage : Storage { - - var contents: String = "" - - constructor(contents: String) { - this.contents = contents - } +class SingleStringStorage(var contents: String) : Storage { override fun getFileContents(file: File): String { return contents } - override fun putFileContents(file: File, putContents: String) { - contents = putContents + override fun putFileContents(file: File, contents: String) { + this.contents = contents } override fun toString(): String { From 40519b92a22dd849288dcea21cb8f0273399953a Mon Sep 17 00:00:00 2001 From: Tim Gunn <2896311+Tornado-Tim@users.noreply.github.com> Date: Sat, 2 May 2020 21:22:21 +1200 Subject: [PATCH 11/12] Fix further tests --- .../nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt | 2 ++ 1 file changed, 2 insertions(+) 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 cd090dbde4..7698cc6844 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt @@ -310,6 +310,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { @Test fun iobAMAShouldBeLimited() { // No limit by default + `when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("closed") `when`(sp.getDouble(R.string.key_openapsma_max_iob, 1.5)).thenReturn(1.5) `when`(sp.getString(R.string.key_age, "")).thenReturn("teenage") openAPSAMAPlugin.setPluginEnabled(PluginType.APS, true) @@ -325,6 +326,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { @Test fun iobSMBShouldBeLimited() { // No limit by default + `when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("closed") `when`(sp.getDouble(R.string.key_openapssmb_max_iob, 3.0)).thenReturn(3.0) `when`(sp.getString(R.string.key_age, "")).thenReturn("teenage") openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true) From 9995e7448b596e79e9f71f4139152b96d3b499f8 Mon Sep 17 00:00:00 2001 From: AdrianLxM Date: Tue, 28 Apr 2020 21:31:25 +0200 Subject: [PATCH 12/12] RandomBGPlugin - stay between min and max The sinus is in interval [-1,1]. If we shift it by one interval it would map it to 0 to 2 times the interval -> divide by two. --- .../info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt index 27f3fd4b4c..bb008b383b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt @@ -79,7 +79,7 @@ class RandomBgPlugin @Inject constructor( val cal = GregorianCalendar() val currentMinute = cal.get(Calendar.MINUTE) + (cal.get(Calendar.HOUR_OF_DAY) % 2) * 60 - val bgMgdl = min + (max - min) + (max - min) * sin(currentMinute / 120.0 * 2 * PI) + val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / 120.0 * 2 * PI))/2 val bgReading = BgReading() bgReading.value = bgMgdl