diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.kt index fb1bb534e0..7dc264c0a4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.kt @@ -36,7 +36,7 @@ open class StorageConstraintPlugin @Inject constructor( ), ConstraintsInterface { override fun isClosedLoopAllowed(value: Constraint): Constraint { - val diskFree = availableInternalMemorySize + val diskFree = availableInternalMemorySize() aapsLogger.debug(LTag.CONSTRAINTS, "Internal storage free (Mb):$diskFree") if (diskFree < Constants.MINIMUM_FREE_SPACE) { value[aapsLogger, false, resourceHelper.gs(R.string.diskfull, Constants.MINIMUM_FREE_SPACE)] = this @@ -48,13 +48,12 @@ open class StorageConstraintPlugin @Inject constructor( return value } - val availableInternalMemorySize: Long - get() { - val path = Environment.getDataDirectory() - val stat = StatFs(path.path) - val blockSize = stat.blockSizeLong - val blocksAvailable = stat.availableBlocksLong - val size = 1048576 // block size of 1 Mb - return blocksAvailable * blockSize / size - } + open fun availableInternalMemorySize(): Long { + val path = Environment.getDataDirectory() + val stat = StatFs(path.path) + val blockSize = stat.blockSizeLong + val blocksAvailable = stat.availableBlocksLong + val size = 1048576 // block size of 1 Mb + return blocksAvailable * blockSize / size + } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt index 2890796171..b70ff5b93a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt @@ -42,7 +42,7 @@ import kotlin.math.min @Singleton class VirtualPumpPlugin @Inject constructor( - injector:HasAndroidInjector, + injector: HasAndroidInjector, aapsLogger: AAPSLogger, private val rxBus: RxBusWrapper, private var fabricPrivacy: FabricPrivacy, @@ -66,6 +66,7 @@ class VirtualPumpPlugin @Inject constructor( companion object { private lateinit var virtualPumpPlugin: VirtualPumpPlugin + @Deprecated("Use dagger to get an instance") fun getPlugin(): VirtualPumpPlugin { checkNotNull(virtualPumpPlugin) { "Accessing VirtualPumpPlugin before first instantiation" } 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 1bdcffe886..9ab76db8ed 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/HardLimits.kt @@ -46,7 +46,11 @@ class HardLimits @Inject constructor( private fun loadAge(): Int { val sp_age = sp.getString(R.string.key_age, "") val age: Int - age = if (sp_age == resourceHelper.gs(R.string.key_child)) CHILD else if (sp_age == resourceHelper.gs(R.string.key_teenage)) TEENAGE else if (sp_age == resourceHelper.gs(R.string.key_adult)) ADULT else if (sp_age == resourceHelper.gs(R.string.key_resistantadult)) RESISTANTADULT else ADULT + age = if (sp_age == resourceHelper.gs(R.string.key_child)) CHILD + else if (sp_age == resourceHelper.gs(R.string.key_teenage)) TEENAGE + else if (sp_age == resourceHelper.gs(R.string.key_adult)) ADULT + else if (sp_age == resourceHelper.gs(R.string.key_resistantadult)) RESISTANTADULT + else ADULT return age } diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.java deleted file mode 100644 index b6bfda8cb1..0000000000 --- a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.java +++ /dev/null @@ -1,243 +0,0 @@ -package info.nightscout.androidaps.plugins.constraints.safety; - -import android.content.Context; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import info.AAPSMocker; -import info.nightscout.androidaps.Constants; -import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.R; -import info.nightscout.androidaps.interfaces.Constraint; -import info.nightscout.androidaps.interfaces.PluginType; -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; -import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin; -import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin; -import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; -import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin; -import info.nightscout.androidaps.plugins.source.GlimpPlugin; -import info.nightscout.androidaps.plugins.treatments.TreatmentService; -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; -import info.nightscout.androidaps.utils.SP; - -import static org.mockito.Mockito.when; - -/** - * Created by mike on 23.03.2018. - */ - -@RunWith(PowerMockRunner.class) -@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, SP.class, Context.class, TreatmentsPlugin.class, TreatmentService.class}) -public class SafetyPluginTest { - - private VirtualPumpPlugin pump = new VirtualPumpPlugin(); - private SafetyPlugin safetyPlugin; - - @Test - public void pumpDescriptionShouldLimitLoopInvocation() { - pump.getPumpDescription().isTempBasalCapable = false; - - Constraint c = new Constraint<>(true); - c = safetyPlugin.isLoopInvocationAllowed(c); - Assert.assertEquals("Safety: Pump is not temp basal capable", c.getReasons()); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - @Test - public void disabledEngineeringModeShouldLimitClosedLoop() { - when(SP.getString(R.string.key_aps_mode, "open")).thenReturn("closed"); - when(MainApp.isEngineeringModeOrRelease()).thenReturn(false); - - Constraint c = new Constraint<>(true); - c = safetyPlugin.isClosedLoopAllowed(c); - Assert.assertTrue(c.getReasons().contains("Running dev version. Closed loop is disabled.")); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - @Test - public void setOpenLoopInPreferencesShouldLimitClosedLoop() { - when(SP.getString(R.string.key_aps_mode, "open")).thenReturn("open"); - - Constraint c = new Constraint<>(true); - c = safetyPlugin.isClosedLoopAllowed(c); - Assert.assertTrue(c.getReasons().contains("Closed loop mode disabled in preferences")); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - @Test - public void notEnabledSMBInPreferencesDisablesSMB() { - when(SP.getBoolean(R.string.key_use_smb, false)).thenReturn(false); - when(ConstraintChecker.getInstance().isClosedLoopAllowed()).thenReturn(new Constraint<>(true)); - - Constraint c = new Constraint<>(true); - c = safetyPlugin.isSMBModeEnabled(c); - Assert.assertTrue(c.getReasons().contains("SMB disabled in preferences")); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - @Test - public void openLoopPreventsSMB() { - when(SP.getBoolean(R.string.key_use_smb, false)).thenReturn(true); - when(ConstraintChecker.getInstance().isClosedLoopAllowed()).thenReturn(new Constraint<>(false)); - - Constraint c = new Constraint<>(true); - c = safetyPlugin.isSMBModeEnabled(c); - Assert.assertTrue(c.getReasons().contains("SMB not allowed in open loop mode")); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - @Test - public void bgSourceShouldPreventSMBAlways() { - when(ConfigBuilderPlugin.getPlugin().getActiveBgSource()).thenReturn(GlimpPlugin.getPlugin()); - - Constraint c = new Constraint<>(true); - c = safetyPlugin.isAdvancedFilteringEnabled(c); - Assert.assertEquals("Safety: SMB always and after carbs disabled because active BG source doesn\\'t support advanced filtering", c.getReasons()); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - @Test - public void basalRateShouldBeLimited() { - when(SP.getDouble(R.string.key_openapsma_max_basal, 1d)).thenReturn(1d); - when(SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d)).thenReturn(4d); - when(SP.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3d)).thenReturn(3d); - when(SP.getString(R.string.key_age, "")).thenReturn("child"); - - Constraint c = new Constraint<>(Constants.REALLYHIGHBASALRATE); - safetyPlugin.applyBasalConstraints(c, AAPSMocker.getValidProfile()); - Assert.assertEquals(1d, c.value(), 0.01d); - Assert.assertEquals("Safety: Limiting basal rate to 1.00 U/h because of max value in preferences\n" + - "Safety: Limiting basal rate to 4.00 U/h because of max basal multiplier\n" + - "Safety: Limiting basal rate to 3.00 U/h because of max daily basal multiplier\n" + - "Safety: Limiting basal rate to 2.00 U/h because of hard limit", c.getReasons()); - Assert.assertEquals("Safety: Limiting basal rate to 1.00 U/h because of max value in preferences", c.getMostLimitedReasons()); - - } - - @Test - public void doNotAllowNegativeBasalRate() { - when(SP.getString(R.string.key_age, "")).thenReturn("child"); - - Constraint d = new Constraint<>(-0.5d); - safetyPlugin.applyBasalConstraints(d, AAPSMocker.getValidProfile()); - Assert.assertEquals(0d, d.value(), 0.01d); - Assert.assertEquals("Safety: Limiting basal rate to 0.00 U/h because of it must be positive value\n" + - "Safety: Increasing max basal value because setting is lower than your max basal in profile", d.getReasons()); - } - - @Test - public void percentBasalRateShouldBeLimited() { - // No limit by default - when(SP.getDouble(R.string.key_openapsma_max_basal, 1d)).thenReturn(1d); - when(SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d)).thenReturn(4d); - when(SP.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3d)).thenReturn(3d); - when(SP.getString(R.string.key_age, "")).thenReturn("child"); - - - Constraint i = new Constraint<>(Constants.REALLYHIGHPERCENTBASALRATE); - safetyPlugin.applyBasalPercentConstraints(i, AAPSMocker.getValidProfile()); - Assert.assertEquals((Integer) 100, i.value()); - Assert.assertEquals("Safety: Percent rate 1111111% recalculated to 11111.11 U/h with current basal 1.00 U/h\n" + - "Safety: Limiting basal rate to 1.00 U/h because of max value in preferences\n" + - "Safety: Limiting basal rate to 4.00 U/h because of max basal multiplier\n" + - "Safety: Limiting basal rate to 3.00 U/h because of max daily basal multiplier\n" + - "Safety: Limiting basal rate to 2.00 U/h because of hard limit\n" + - "Safety: Limiting percent rate to 100% because of pump limit", i.getReasons()); - Assert.assertEquals("Safety: Limiting percent rate to 100% because of pump limit", i.getMostLimitedReasons()); - } - - @Test - public void doNotAllowNegativePercentBasalRate() { - when(SP.getString(R.string.key_age, "")).thenReturn("child"); - - Constraint i = new Constraint<>(-22); - safetyPlugin.applyBasalPercentConstraints(i, AAPSMocker.getValidProfile()); - Assert.assertEquals((Integer) 0, i.value()); - Assert.assertEquals("Safety: Percent rate -22% recalculated to -0.22 U/h with current basal 1.00 U/h\n" + - "Safety: Limiting basal rate to 0.00 U/h because of it must be positive value\n" + - "Safety: Increasing max basal value because setting is lower than your max basal in profile\n" + - "Safety: Limiting percent rate to 0% because of pump limit", i.getReasons()); - Assert.assertEquals("Safety: Limiting percent rate to 0% because of pump limit", i.getMostLimitedReasons()); - } - - @Test - public void bolusAmountShouldBeLimited() { - when(SP.getDouble(R.string.key_treatmentssafety_maxbolus, 3d)).thenReturn(3d); - when(SP.getString(R.string.key_age, "")).thenReturn("child"); - - Constraint d = new Constraint<>(Constants.REALLYHIGHBOLUS); - d = safetyPlugin.applyBolusConstraints(d); - Assert.assertEquals(3d, d.value(), 0.01d); - Assert.assertEquals("Safety: Limiting bolus to 3.0 U because of max value in preferences\n" + - "Safety: Limiting bolus to 5.0 U because of hard limit", d.getReasons()); - Assert.assertEquals("Safety: Limiting bolus to 3.0 U because of max value in preferences", d.getMostLimitedReasons()); - } - - @Test - public void doNotAllowNegativeBolusAmount() { - when(SP.getDouble(R.string.key_treatmentssafety_maxbolus, 3d)).thenReturn(3d); - when(SP.getString(R.string.key_age, "")).thenReturn("child"); - - Constraint d = new Constraint<>(-22d); - d = safetyPlugin.applyBolusConstraints(d); - Assert.assertEquals(0d, d.value(), 0.01d); - Assert.assertEquals("Safety: Limiting bolus to 0.0 U because of it must be positive value", d.getReasons()); - Assert.assertEquals("Safety: Limiting bolus to 0.0 U because of it must be positive value", d.getMostLimitedReasons()); - } - - @Test - public void carbsAmountShouldBeLimited() { - // No limit by default - when(SP.getInt(R.string.key_treatmentssafety_maxcarbs, 48)).thenReturn(48); - - // Negative carbs not allowed - Constraint i = new Constraint<>(-22); - safetyPlugin.applyCarbsConstraints(i); - Assert.assertEquals((Integer) 0, i.value()); - Assert.assertEquals("Safety: Limiting carbs to 0 g because of it must be positive value", i.getReasons()); - - // Apply all limits - i = safetyPlugin.applyCarbsConstraints(new Constraint<>(Constants.REALLYHIGHCARBS)); - Assert.assertEquals((Integer) 48, i.value()); - Assert.assertEquals("Safety: Limiting carbs to 48 g because of max value in preferences", i.getReasons()); - } - - @Test - public void iobShouldBeLimited() { - when(SP.getDouble(R.string.key_openapsma_max_iob, 1.5d)).thenReturn(1.5d); - when(SP.getString(R.string.key_age, "")).thenReturn("teenage"); - OpenAPSMAPlugin.getPlugin().setPluginEnabled(PluginType.APS, true); - OpenAPSAMAPlugin.getPlugin().setPluginEnabled(PluginType.APS, true); - //OpenAPSSMBPlugin.getPlugin().setPluginEnabled(PluginType.APS, true); - - // Apply all limits - Constraint d = new Constraint<>(Constants.REALLYHIGHIOB); - d = safetyPlugin.applyMaxIOBConstraints(d); - Assert.assertEquals(1.5d, d.value(), 0.01d); - Assert.assertEquals("Safety: Limiting IOB to 1.5 U because of max value in preferences\n" + - "Safety: Limiting IOB to 7.0 U because of hard limit\n" + - "Safety: Limiting IOB to 7.0 U because of hard limit", d.getReasons()); - Assert.assertEquals("Safety: Limiting IOB to 1.5 U because of max value in preferences", d.getMostLimitedReasons()); - } - - @Before - public void prepareMock() { - AAPSMocker.mockMainApp(); - AAPSMocker.mockConfigBuilder(); - AAPSMocker.mockConstraintsChecker(); - AAPSMocker.mockSP(); - AAPSMocker.mockStrings(); - AAPSMocker.mockTreatmentService(); - AAPSMocker.mockTreatmentPlugin(); - - - when(ConfigBuilderPlugin.getPlugin().getActivePump()).thenReturn(pump); - - safetyPlugin = SafetyPlugin.getPlugin(); - } -} 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 new file mode 100644 index 0000000000..4473e3dd5d --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt @@ -0,0 +1,247 @@ +package info.nightscout.androidaps.plugins.constraints.safety + +import android.content.Context +import dagger.android.AndroidInjector +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.R +import info.nightscout.androidaps.TestBaseWithProfile +import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.interfaces.PumpDescription +import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin +import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin +import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin +import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker +import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin +import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin +import info.nightscout.androidaps.plugins.source.GlimpPlugin +import info.nightscout.androidaps.utils.HardLimits +import info.nightscout.androidaps.utils.buildHelper.BuildHelper +import info.nightscout.androidaps.utils.sharedPreferences.SP +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.powermock.core.classloader.annotations.PrepareForTest +import org.powermock.modules.junit4.PowerMockRunner + +@RunWith(PowerMockRunner::class) +@PrepareForTest(ConstraintChecker::class, BuildHelper::class, VirtualPumpPlugin::class, GlimpPlugin::class) +class SafetyPluginTest : TestBaseWithProfile() { + + @Mock lateinit var sp: SP + @Mock lateinit var constraintChecker: ConstraintChecker + @Mock lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin + @Mock lateinit var openAPSMAPlugin: OpenAPSMAPlugin + @Mock lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin + @Mock lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin + @Mock lateinit var activePlugin: ActivePluginProvider + @Mock lateinit var buildHelper: BuildHelper + @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin + @Mock lateinit var glimpPlugin: GlimpPlugin + @Mock lateinit var context: Context + + private lateinit var hardLimits: HardLimits + private lateinit var safetyPlugin: SafetyPlugin + + val injector = HasAndroidInjector { AndroidInjector { } } + val pumpDescription = PumpDescription() + + @Before + fun prepare() { + `when`(resourceHelper.gs(R.string.limitingbolus)).thenReturn("Limiting bolus to %1\$.1f U because of %2\$s") + `when`(resourceHelper.gs(R.string.limitingbasalratio)).thenReturn("Limiting max basal rate to %1\$.2f U/h because of %2\$s") + `when`(resourceHelper.gs(R.string.limitingiob)).thenReturn("Limiting IOB to %1\$.1f U because of %2\$s") + `when`(resourceHelper.gs(R.string.limitingcarbs)).thenReturn("Limiting carbs to %1\$d g because of %2\$s") + `when`(resourceHelper.gs(R.string.limitingpercentrate)).thenReturn("Limiting max percent rate to %1\$d%% because of %2\$s") + `when`(resourceHelper.gs(R.string.pumpisnottempbasalcapable)).thenReturn("Pump is not temp basal capable") + `when`(resourceHelper.gs(R.string.increasingmaxbasal)).thenReturn("Increasing max basal value because setting is lower than your max basal in profile") + `when`(resourceHelper.gs(R.string.smbdisabledinpreferences)).thenReturn("SMB disabled in preferences") + `when`(resourceHelper.gs(R.string.closedmodedisabledinpreferences)).thenReturn("Closed loop mode disabled in preferences") + `when`(resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch)).thenReturn("Running dev version. Closed loop is disabled.") + `when`(resourceHelper.gs(R.string.itmustbepositivevalue)).thenReturn("it must be positive value") + `when`(resourceHelper.gs(R.string.pumplimit)).thenReturn("pump limit") + `when`(resourceHelper.gs(R.string.smbalwaysdisabled)).thenReturn("SMB always and after carbs disabled because active BG source doesn\\'t support advanced filtering") + `when`(resourceHelper.gs(R.string.smbnotallowedinopenloopmode)).thenReturn("SMB not allowed in open loop mode") + `when`(resourceHelper.gs(R.string.maxvalueinpreferences)).thenReturn("max value in preferences") + `when`(resourceHelper.gs(R.string.maxbasalmultiplier)).thenReturn("max basal multiplier") + `when`(resourceHelper.gs(R.string.maxdailybasalmultiplier)).thenReturn("max daily basal multiplier") + `when`(resourceHelper.gs(R.string.hardlimit)).thenReturn("hard limit") + `when`(resourceHelper.gs(R.string.key_child)).thenReturn("child") + + `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) + `when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription) + hardLimits = HardLimits(aapsLogger, sp, resourceHelper, context) + safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin) + } + + @Test fun pumpDescriptionShouldLimitLoopInvocation() { + pumpDescription.isTempBasalCapable = false + var c = Constraint(true) + c = safetyPlugin.isLoopInvocationAllowed(c) + Assert.assertEquals("Safety: Pump is not temp basal capable", c.getReasons(aapsLogger)) + Assert.assertEquals(false, c.value()) + } + + @Test fun disabledEngineeringModeShouldLimitClosedLoop() { + `when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("closed") + `when`(buildHelper.isEngineeringModeOrRelease()).thenReturn(false) + var c = Constraint(true) + c = safetyPlugin.isClosedLoopAllowed(c) + Assert.assertTrue(c.getReasons(aapsLogger).contains("Running dev version. Closed loop is disabled.")) + Assert.assertEquals(false, c.value()) + } + + @Test fun setOpenLoopInPreferencesShouldLimitClosedLoop() { + `when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("open") + var c = Constraint(true) + c = safetyPlugin.isClosedLoopAllowed(c) + Assert.assertTrue(c.getReasons(aapsLogger).contains("Closed loop mode disabled in preferences")) + Assert.assertEquals(false, c.value()) + } + + @Test fun notEnabledSMBInPreferencesDisablesSMB() { + `when`(sp.getBoolean(R.string.key_use_smb, false)).thenReturn(false) + `when`(constraintChecker.isClosedLoopAllowed()).thenReturn(Constraint(true)) + var c = Constraint(true) + c = safetyPlugin.isSMBModeEnabled(c) + Assert.assertTrue(c.getReasons(aapsLogger).contains("SMB disabled in preferences")) + Assert.assertEquals(false, c.value()) + } + + @Test fun openLoopPreventsSMB() { + `when`(sp.getBoolean(R.string.key_use_smb, false)).thenReturn(true) + `when`(constraintChecker.isClosedLoopAllowed()).thenReturn(Constraint(false)) + var c = Constraint(true) + c = safetyPlugin.isSMBModeEnabled(c) + Assert.assertTrue(c.getReasons(aapsLogger).contains("SMB not allowed in open loop mode")) + Assert.assertEquals(false, c.value()) + } + + @Test fun bgSourceShouldPreventSMBAlways() { + `when`(activePlugin.activeBgSource).thenReturn(glimpPlugin) + var c = Constraint(true) + c = safetyPlugin.isAdvancedFilteringEnabled(c) + Assert.assertEquals("Safety: SMB always and after carbs disabled because active BG source doesn\\'t support advanced filtering", c.getReasons(aapsLogger)) + Assert.assertEquals(false, c.value()) + } + + @Test fun basalRateShouldBeLimited() { + `when`(sp.getDouble(R.string.key_openapsma_max_basal, 1.0)).thenReturn(1.0) + `when`(sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0)).thenReturn(4.0) + `when`(sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3.0)).thenReturn(3.0) + `when`(sp.getString(R.string.key_age, "")).thenReturn("child") + val c = Constraint(Constants.REALLYHIGHBASALRATE) + safetyPlugin.applyBasalConstraints(c, validProfile) + Assert.assertEquals(1.0, c.value(), 0.01) + Assert.assertEquals(""" + Safety: Limiting max basal rate to 1.00 U/h because of max value in preferences + Safety: Limiting max basal rate to 4.00 U/h because of max basal multiplier + Safety: Limiting max basal rate to 3.00 U/h because of max daily basal multiplier + Safety: Limiting max basal rate to 2.00 U/h because of hard limit + """.trimIndent(), c.getReasons(aapsLogger)) + Assert.assertEquals("Safety: Limiting max basal rate to 1.00 U/h because of max value in preferences", c.getMostLimitedReasons(aapsLogger)) + } + + @Test fun doNotAllowNegativeBasalRate() { + `when`(sp.getString(R.string.key_age, "")).thenReturn("child") + val d = Constraint(-0.5) + safetyPlugin.applyBasalConstraints(d, validProfile) + Assert.assertEquals(0.0, d.value(), 0.01) + Assert.assertEquals(""" + Safety: Limiting max basal rate to 0.00 U/h because of it must be positive value + Safety: Increasing max basal value because setting is lower than your max basal in profile + """.trimIndent(), d.getReasons(aapsLogger)) + } + + @Test fun percentBasalRateShouldBeLimited() { + // No limit by default + `when`(sp.getDouble(R.string.key_openapsma_max_basal, 1.0)).thenReturn(1.0) + `when`(sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0)).thenReturn(4.0) + `when`(sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3.0)).thenReturn(3.0) + `when`(sp.getString(R.string.key_age, "")).thenReturn("child") + val i = Constraint(Constants.REALLYHIGHPERCENTBASALRATE) + safetyPlugin.applyBasalPercentConstraints(i, validProfile) + Assert.assertEquals(100, i.value()) + Assert.assertEquals(""" + Safety: Percent rate 1111111% recalculated to 11111.11 U/h with current basal 1.00 U/h + Safety: Limiting max basal rate to 1.00 U/h because of max value in preferences + Safety: Limiting max basal rate to 4.00 U/h because of max basal multiplier + Safety: Limiting max basal rate to 3.00 U/h because of max daily basal multiplier + Safety: Limiting max basal rate to 2.00 U/h because of hard limit + Safety: Limiting max percent rate to 100% because of pump limit + Safety: Limiting max basal rate to 500.00 U/h because of pump limit + """.trimIndent(), i.getReasons(aapsLogger)) + Assert.assertEquals("Safety: Limiting max percent rate to 100% because of pump limit", i.getMostLimitedReasons(aapsLogger)) + } + + @Test fun doNotAllowNegativePercentBasalRate() { + `when`(sp.getString(R.string.key_age, "")).thenReturn("child") + val i = Constraint(-22) + safetyPlugin.applyBasalPercentConstraints(i, validProfile) + Assert.assertEquals(0, i.value()) + Assert.assertEquals(""" + Safety: Percent rate -22% recalculated to -0.22 U/h with current basal 1.00 U/h + Safety: Limiting max basal rate to 0.00 U/h because of it must be positive value + Safety: Increasing max basal value because setting is lower than your max basal in profile + Safety: Limiting max percent rate to 0% because of pump limit + """.trimIndent(), i.getReasons(aapsLogger)) + Assert.assertEquals("Safety: Limiting max percent rate to 0% because of pump limit", i.getMostLimitedReasons(aapsLogger)) + } + + @Test fun bolusAmountShouldBeLimited() { + `when`(sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)).thenReturn(3.0) + `when`(sp.getString(R.string.key_age, "")).thenReturn("child") + var d = Constraint(Constants.REALLYHIGHBOLUS) + d = safetyPlugin.applyBolusConstraints(d) + Assert.assertEquals(3.0, d.value()!!, 0.01) + Assert.assertEquals(""" + Safety: Limiting bolus to 3.0 U because of max value in preferences + Safety: Limiting bolus to 5.0 U because of hard limit + """.trimIndent(), d.getReasons(aapsLogger)) + Assert.assertEquals("Safety: Limiting bolus to 3.0 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger)) + } + + @Test fun doNotAllowNegativeBolusAmount() { + `when`(sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)).thenReturn(3.0) + `when`(sp.getString(R.string.key_age, "")).thenReturn("child") + var d = Constraint(-22.0) + d = safetyPlugin.applyBolusConstraints(d) + Assert.assertEquals(0.0, d.value(), 0.01) + Assert.assertEquals("Safety: Limiting bolus to 0.0 U because of it must be positive value", d.getReasons(aapsLogger)) + Assert.assertEquals("Safety: Limiting bolus to 0.0 U because of it must be positive value", d.getMostLimitedReasons(aapsLogger)) + } + + @Test fun carbsAmountShouldBeLimited() { + // No limit by default + `when`(sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48)).thenReturn(48) + + // Negative carbs not allowed + var i = Constraint(-22) + safetyPlugin.applyCarbsConstraints(i) + Assert.assertEquals(0, i.value()) + Assert.assertEquals("Safety: Limiting carbs to 0 g because of it must be positive value", i.getReasons(aapsLogger)) + + // Apply all limits + i = safetyPlugin.applyCarbsConstraints(Constraint(Constants.REALLYHIGHCARBS)) + Assert.assertEquals(48, i.value()) + Assert.assertEquals("Safety: Limiting carbs to 48 g because of max value in preferences", i.getReasons(aapsLogger)) + } + + @Test fun iobShouldBeLimited() { + `when`(sp.getDouble(R.string.key_openapsma_max_iob, 1.5)).thenReturn(1.5) + `when`(sp.getString(R.string.key_age, "")).thenReturn("teenage") + + // Apply all limits + var d = Constraint(Constants.REALLYHIGHIOB) + d = safetyPlugin.applyMaxIOBConstraints(d) + Assert.assertEquals(1.5, d.value()!!, 0.01) + Assert.assertEquals(""" + Safety: Limiting IOB to 1.5 U because of max value in preferences + """.trimIndent(), d.getReasons(aapsLogger)) + Assert.assertEquals("Safety: Limiting IOB to 1.5 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger)) + } +} \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPluginTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPluginTest.java deleted file mode 100644 index bd118d1391..0000000000 --- a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPluginTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package info.nightscout.androidaps.plugins.constraints.storage; - -import android.os.Environment; -import android.os.StatFs; - -import junit.framework.Assert; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import java.io.File; - -import info.AAPSMocker; -import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.interfaces.Constraint; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.whenNew; - -/** - * Created by Rumen on 06.03.2019. - */ - -@RunWith(PowerMockRunner.class) -@PrepareForTest({MainApp.class, StorageConstraintPlugin.class, StatFs.class, Environment.class}) -public class StorageConstraintPluginTest extends StorageConstraintPlugin{ - - StorageConstraintPlugin storageConstraintPlugin; - private File mockedFile; - private static final String path = "/data"; - private StatFs mockedStatFs; - - @Test - public void isLoopInvocationAllowedTest(){ - PowerMockito.mockStatic(StorageConstraintPlugin.class); - // Set free space under 200(Mb) to disable loop - when(StorageConstraintPlugin.getAvailableInternalMemorySize()).thenReturn(150L); - Constraint c = new Constraint<>(true); - c = storageConstraintPlugin.isClosedLoopAllowed(c); - Assert.assertEquals(Boolean.FALSE, c.value()); - // Set free space over 200(Mb) to enable loop - when(StorageConstraintPlugin.getAvailableInternalMemorySize()).thenReturn(300L); - Constraint c2 = new Constraint<>(true); - c2 = storageConstraintPlugin.isClosedLoopAllowed(c2); - Assert.assertEquals(Boolean.TRUE, c2.value()); - } - - @Test - public void getAvailableInternalMemorySizeTest() throws Exception { - PowerMockito.mockStatic(Environment.class); - PowerMockito.when(Environment.getDataDirectory()).thenReturn(mockedFile); - when(mockedFile.getPath()).thenReturn(path); - when(mockedFile.exists()).thenReturn(true); - - whenNew(StatFs.class).withArguments(any()).thenReturn(mockedStatFs); - when(mockedStatFs.getBlockSizeLong()).thenReturn(1024L); - when(mockedStatFs.getAvailableBlocksLong()).thenReturn(150l*1024); - - long freeSpaceInMb = storageConstraintPlugin.getAvailableInternalMemorySize(); - Assert.assertEquals(150L, freeSpaceInMb); - - } - - - @Before - public void prepareMock() { - AAPSMocker.mockMainApp(); - AAPSMocker.mockStrings(); - mockedFile = mock(File.class); - mockedStatFs = mock(StatFs.class); - storageConstraintPlugin = StorageConstraintPlugin.getPlugin(); - } -} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPluginTest.kt new file mode 100644 index 0000000000..556802036b --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPluginTest.kt @@ -0,0 +1,53 @@ +package info.nightscout.androidaps.plugins.constraints.storage + +import android.os.Environment +import android.os.StatFs +import dagger.android.AndroidInjector +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.TestBase +import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.utils.resources.ResourceHelper +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.powermock.core.classloader.annotations.PrepareForTest +import org.powermock.modules.junit4.PowerMockRunner + +@RunWith(PowerMockRunner::class) +class StorageConstraintPluginTest : TestBase() { + + @Mock lateinit var aapsLogger: AAPSLogger + @Mock lateinit var resourceHelper: ResourceHelper + private val rxBusWrapper = RxBusWrapper() + + lateinit var storageConstraintPlugin: StorageConstraintPlugin + + @Before fun prepareMock() { + storageConstraintPlugin = StorageConstraintPlugin(HasAndroidInjector { AndroidInjector { } }, aapsLogger, resourceHelper, rxBusWrapper) + } + + class MockedStorageConstraintPlugin constructor( + injector: HasAndroidInjector, + aapsLogger: AAPSLogger, + resourceHelper: ResourceHelper, + private val rxBus: RxBusWrapper + ) : StorageConstraintPlugin(injector, aapsLogger, resourceHelper, rxBus) { + + var memSize = 150L + override fun availableInternalMemorySize(): Long = memSize + } + + @Test fun isLoopInvocationAllowedTest() { + val mocked = MockedStorageConstraintPlugin(HasAndroidInjector { AndroidInjector { } }, aapsLogger, resourceHelper, rxBusWrapper) + // Set free space under 200(Mb) to disable loop + mocked.memSize = 150L + Assert.assertEquals(false, mocked.isClosedLoopAllowed(Constraint(true)).value()) + // Set free space over 200(Mb) to enable loop + mocked.memSize = 300L + Assert.assertEquals(true, mocked.isClosedLoopAllowed(Constraint(true)).value()) + } +} \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPluginUTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPluginUTest.java deleted file mode 100644 index 0a9d68c1ad..0000000000 --- a/app/src/test/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPluginUTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.virtual; - -import android.content.Context; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import info.AAPSMocker; -import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.R; -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; -import info.nightscout.androidaps.utils.SP; -import info.nightscout.androidaps.utils.ToastUtils; - -import static org.powermock.api.mockito.PowerMockito.when; - -/** - * Created by andy on 5/13/18. - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class, SP.class}) -public class VirtualPumpPluginUTest { - - - VirtualPumpPlugin virtualPumpPlugin; - - - - @Before - public void prepareMocks() throws Exception { - AAPSMocker.mockMainApp(); - AAPSMocker.mockConfigBuilder(); - AAPSMocker.mockStrings(); - AAPSMocker.mockCommandQueue(); - AAPSMocker.mockSP(); - - virtualPumpPlugin = VirtualPumpPlugin.getPlugin(); - } - - - @Test - public void getPumpType() { - } - - @Test - public void refreshConfiguration() { - - when(SP.getString(R.string.key_virtualpump_type, "Generic AAPS")).thenReturn("Accu-Chek Combo"); - - virtualPumpPlugin.refreshConfiguration(); - - Assert.assertEquals(PumpType.AccuChekCombo, virtualPumpPlugin.getPumpType()); - } - - - @Test - public void refreshConfigurationTwice() { - - when(SP.getString(R.string.key_virtualpump_type, "Generic AAPS")).thenReturn("Accu-Chek Combo"); - - virtualPumpPlugin.refreshConfiguration(); - - when(SP.getString(R.string.key_virtualpump_type, "Generic AAPS")).thenReturn("Accu-Chek Combo"); - - virtualPumpPlugin.refreshConfiguration(); - - Assert.assertEquals(PumpType.AccuChekCombo, virtualPumpPlugin.getPumpType()); - } - -} \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPluginUTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPluginUTest.kt new file mode 100644 index 0000000000..ed9ec5aa14 --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPluginUTest.kt @@ -0,0 +1,60 @@ +package info.nightscout.androidaps.plugins.pump.virtual + +import dagger.android.AndroidInjector +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.R +import info.nightscout.androidaps.TestBase +import info.nightscout.androidaps.interfaces.CommandQueueProvider +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.sharedPreferences.SP +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.powermock.api.mockito.PowerMockito +import org.powermock.core.classloader.annotations.PrepareForTest +import org.powermock.modules.junit4.PowerMockRunner + +@RunWith(PowerMockRunner::class) +@PrepareForTest(FabricPrivacy::class) +class VirtualPumpPluginUTest : TestBase() { + + @Mock lateinit var aapsLogger: AAPSLogger + val rxBus = RxBusWrapper() + @Mock lateinit var fabricPrivacy: FabricPrivacy + @Mock lateinit var resourceHelper: ResourceHelper + @Mock lateinit var sp: SP + @Mock lateinit var profileFunction: ProfileFunction + @Mock lateinit var treatmentsPlugin: TreatmentsPlugin + @Mock lateinit var commandQueue: CommandQueueProvider + + lateinit var virtualPumpPlugin: VirtualPumpPlugin + + @Before + fun prepareMocks() { + virtualPumpPlugin = VirtualPumpPlugin(HasAndroidInjector { AndroidInjector { } }, aapsLogger, rxBus, fabricPrivacy, resourceHelper, sp, profileFunction, treatmentsPlugin, commandQueue) + } + + @Test + fun refreshConfiguration() { + PowerMockito.`when`(sp.getString(R.string.key_virtualpump_type, "Generic AAPS")).thenReturn("Accu-Chek Combo") + virtualPumpPlugin.refreshConfiguration() + Assert.assertEquals(PumpType.AccuChekCombo, virtualPumpPlugin.pumpType) + } + + @Test + fun refreshConfigurationTwice() { + PowerMockito.`when`(sp.getString(R.string.key_virtualpump_type, "Generic AAPS")).thenReturn("Accu-Chek Combo") + virtualPumpPlugin.refreshConfiguration() + PowerMockito.`when`(sp.getString(R.string.key_virtualpump_type, "Generic AAPS")).thenReturn("Accu-Chek Combo") + virtualPumpPlugin.refreshConfiguration() + Assert.assertEquals(PumpType.AccuChekCombo, virtualPumpPlugin.pumpType) + } +} \ No newline at end of file