From 15d8719508a158089f12fa496ecf6dee54df98c3 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Fri, 23 Mar 2018 17:36:49 +0100 Subject: [PATCH] collect most limited reason along with all reasons --- .../androidaps/interfaces/Constraint.java | 34 ++- .../ConstraintsSafety/SafetyPlugin.java | 2 +- app/src/main/res/values-cs/strings.xml | 2 +- app/src/test/java/info/AAPSMocker.java | 94 +++++++ .../androidaps/PumpDanaR/DanaRPluginTest.java | 76 ++++++ .../androidaps/interfaces/ConstraintTest.java | 7 + .../interfaces/ConstraintsCheckerTest.java | 250 ++++-------------- .../ObjectivesPluginTest.java | 90 +++++++ .../ConstraintsSafety/SafetyPluginTest.java | 214 +++++++++++++++ .../plugins/PumpCombo/ComboPluginTest.java | 54 ++-- .../plugins/PumpDanaRS/DanaRSPluginTest.java | 75 ++++++ .../plugins/PumpInsight/PumpInsightTest.java | 56 ++++ 12 files changed, 724 insertions(+), 230 deletions(-) create mode 100644 app/src/test/java/info/AAPSMocker.java create mode 100644 app/src/test/java/info/nightscout/androidaps/PumpDanaR/DanaRPluginTest.java create mode 100644 app/src/test/java/info/nightscout/androidaps/plugins/ConstraintsObjectives/ObjectivesPluginTest.java create mode 100644 app/src/test/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPluginTest.java create mode 100644 app/src/test/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPluginTest.java create mode 100644 app/src/test/java/info/nightscout/androidaps/plugins/PumpInsight/PumpInsightTest.java diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/Constraint.java b/app/src/main/java/info/nightscout/androidaps/interfaces/Constraint.java index 7b6609b79c..58e6045bd1 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/Constraint.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/Constraint.java @@ -17,6 +17,7 @@ public class Constraint { T originalValue; List reasons = new ArrayList<>(); + List mostLimiting = new ArrayList<>(); public Constraint(T value) { this.value = value; @@ -39,16 +40,19 @@ public class Constraint { public Constraint set(T value, String reason, Object from) { this.value = value; - reason(reason, from); + addReason(reason, from); + addMostLimingReason(reason, from); return this; } public Constraint setIfSmaller(T value, String reason, Object from) { if (value.compareTo(this.value) < 0) { this.value = value; + mostLimiting.clear(); + addMostLimingReason(reason, from); } if (value.compareTo(this.originalValue) < 0) { - reason(reason, from); + addReason(reason, from); } return this; } @@ -56,18 +60,25 @@ public class Constraint { public Constraint setIfGreater(T value, String reason, Object from) { if (value.compareTo(this.value) > 0) { this.value = value; + mostLimiting.clear(); + addMostLimingReason(reason, from); } if (value.compareTo(this.originalValue) > 0) { - reason(reason, from); + addReason(reason, from); } return this; } - public Constraint reason(String reason, Object from) { + public Constraint addReason(String reason, Object from) { reasons.add(from.getClass().getSimpleName().replace("Plugin", "") + ": " + reason); return this; } + public Constraint addMostLimingReason(String reason, Object from) { + mostLimiting.add(from.getClass().getSimpleName().replace("Plugin", "") + ": " + reason); + return this; + } + public String getReasons() { StringBuilder sb = new StringBuilder(); int count = 0; @@ -83,6 +94,21 @@ public class Constraint { return reasons; } + public String getMostLimitedReasons() { + StringBuilder sb = new StringBuilder(); + int count = 0; + for (String r : mostLimiting) { + if (count++ != 0) sb.append("\n"); + sb.append(r); + } + log.debug("Limiting origial value: " + originalValue + " to " + value + ". Reason: " + sb.toString()); + return sb.toString(); + } + + public List getMostLimitedReasonList() { + return mostLimiting; + } + public void copyReasons(Constraint another) { for (String s: another.getReasonList()) { reasons.add(s); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPlugin.java index 048e48f8b3..7194380360 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPlugin.java @@ -156,7 +156,7 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface { Double currentBasal = profile.getBasal(); Double absoluteRate = currentBasal * ((double) percentRate.originalValue() / 100); - percentRate.reason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this); + percentRate.addReason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this); Constraint absoluteConstraint = new Constraint<>(absoluteRate); applyBasalConstraints(absoluteConstraint, profile); diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 30cd42c89e..4ce126527c 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -734,7 +734,7 @@ Použít super mikro bolusy místo dočasných bazálů pro zrychlení účinku Detekce neoznámených jídel Insight - Pumpa Insight + Insight Stav Změněno PUMPA ZASTAVENA diff --git a/app/src/test/java/info/AAPSMocker.java b/app/src/test/java/info/AAPSMocker.java new file mode 100644 index 0000000000..adf5136dd0 --- /dev/null +++ b/app/src/test/java/info/AAPSMocker.java @@ -0,0 +1,94 @@ +package info; + +import android.content.Context; + +import com.squareup.otto.Bus; + +import org.json.JSONException; +import org.json.JSONObject; +import org.powermock.api.mockito.PowerMockito; + +import java.util.Locale; + +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.utils.SP; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Created by mike on 23.03.2018. + */ + +public class AAPSMocker { + static String validProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"},{\"time\":\"2:00\",\"value\":\"110\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"; + static Profile profile; + + public static void mockStrings() { + Locale.setDefault(new Locale("en", "US")); + + when(MainApp.gs(R.string.closed_loop_disabled_on_dev_branch)).thenReturn("Running dev version. Closed loop is disabled."); + when(MainApp.gs(R.string.closedmodedisabledinpreferences)).thenReturn("Closed loop mode disabled in preferences"); + when(MainApp.gs(R.string.objectivenotstarted)).thenReturn("Objective %d not started"); + when(MainApp.gs(R.string.novalidbasalrate)).thenReturn("No valid basal rate read from pump"); + when(MainApp.gs(R.string.autosensdisabledinpreferences)).thenReturn("Autosens disabled in preferences"); + when(MainApp.gs(R.string.smbdisabledinpreferences)).thenReturn("SMB disabled in preferences"); + when(MainApp.gs(R.string.limitingbasalratio)).thenReturn("Limiting basal rate to %.2f U/h because of %s"); + when(MainApp.gs(R.string.pumplimit)).thenReturn("pump limit"); + when(MainApp.gs(R.string.itmustbepositivevalue)).thenReturn("it must be positive value"); + when(MainApp.gs(R.string.maxvalueinpreferences)).thenReturn("max value in preferences"); + when(MainApp.gs(R.string.maxbasalmultiplier)).thenReturn("max basal multiplier"); + when(MainApp.gs(R.string.maxdailybasalmultiplier)).thenReturn("max daily basal multiplier"); + when(MainApp.gs(R.string.limitingpercentrate)).thenReturn("Limiting percent rate to %d%% because of %s"); + when(MainApp.gs(R.string.pumplimit)).thenReturn("pump limit"); + when(MainApp.gs(R.string.limitingbolus)).thenReturn("Limiting bolus to %.1f U because of %s"); + when(MainApp.gs(R.string.hardlimit)).thenReturn("hard limit"); + when(MainApp.gs(R.string.key_child)).thenReturn("child"); + when(MainApp.gs(R.string.limitingcarbs)).thenReturn("Limiting carbs to %d g because of %s"); + when(MainApp.gs(R.string.limitingiob)).thenReturn("Limiting IOB to %.1f U because of %s"); + when(MainApp.gs(R.string.pumpisnottempbasalcapable)).thenReturn("Pump is not temp basal capable"); + } + + public static MainApp mockMainApp() { + PowerMockito.mockStatic(MainApp.class); + MainApp mainApp = mock(MainApp.class); + when(MainApp.instance()).thenReturn(mainApp); + return mainApp; + } + + public static void mockConfigBuilder() { + PowerMockito.mockStatic(ConfigBuilderPlugin.class); + ConfigBuilderPlugin configBuilderPlugin = mock(ConfigBuilderPlugin.class); + when(MainApp.getConfigBuilder()).thenReturn(configBuilderPlugin); + } + + public static void mockBus() { + Bus bus = PowerMockito.mock(Bus.class); + when(MainApp.bus()).thenReturn(bus); + } + + public static void mockSP() { + PowerMockito.mockStatic(SP.class); + when(SP.getLong(anyInt(), anyLong())).thenReturn(0L); + when(SP.getBoolean(anyInt(), anyBoolean())).thenReturn(false); + when(SP.getInt(anyInt(), anyInt())).thenReturn(0); + } + + public static void mockApplicationContext() { + Context context = mock(Context.class); + when(MainApp.instance().getApplicationContext()).thenReturn(context); + } + + public static Profile getValidProfile() throws JSONException { + if (profile == null) + profile = new Profile(new JSONObject(validProfile), Constants.MGDL); + return profile; + } +} diff --git a/app/src/test/java/info/nightscout/androidaps/PumpDanaR/DanaRPluginTest.java b/app/src/test/java/info/nightscout/androidaps/PumpDanaR/DanaRPluginTest.java new file mode 100644 index 0000000000..5f288dc9c7 --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/PumpDanaR/DanaRPluginTest.java @@ -0,0 +1,76 @@ +package info.nightscout.androidaps.PumpDanaR; + +import android.content.Context; + +import junit.framework.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.PluginBase; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; +import info.nightscout.utils.SP; +import info.nightscout.utils.ToastUtils; + +import static org.mockito.Mockito.when; + +/** + * Created by mike on 23.03.2018. + */ + +@RunWith(PowerMockRunner.class) +@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class, SP.class}) +public class DanaRPluginTest { + + DanaRPlugin danaRPlugin; + + @Test + public void basalRateShouldBeLimited() throws Exception { + danaRPlugin.setFragmentEnabled(PluginBase.PUMP, true); + danaRPlugin.setFragmentEnabled(PluginBase.PUMP, true); + DanaRPump.getInstance().maxBasal = 0.8d; + + Constraint c = new Constraint<>(Constants.REALLYHIGHBASALRATE); + danaRPlugin.applyBasalConstraints(c, AAPSMocker.getValidProfile()); + Assert.assertEquals(0.8d, c.value()); + Assert.assertEquals("DanaR: Limiting basal rate to 0.80 U/h because of pump limit", c.getReasons()); + Assert.assertEquals("DanaR: Limiting basal rate to 0.80 U/h because of pump limit", c.getMostLimitedReasons()); + } + + @Test + public void percentBasalRateShouldBeLimited() throws Exception { + danaRPlugin.setFragmentEnabled(PluginBase.PUMP, true); + danaRPlugin.setFragmentEnabled(PluginBase.PUMP, true); + DanaRPump.getInstance().maxBasal = 0.8d; + + Constraint c = new Constraint<>(Constants.REALLYHIGHPERCENTBASALRATE); + danaRPlugin.applyBasalPercentConstraints(c, AAPSMocker.getValidProfile()); + Assert.assertEquals((Integer) 200, c.value()); + Assert.assertEquals("DanaR: Limiting percent rate to 200% because of pump limit", c.getReasons()); + Assert.assertEquals("DanaR: Limiting percent rate to 200% because of pump limit", c.getMostLimitedReasons()); + } + + @Before + public void prepareMocks() throws Exception { + AAPSMocker.mockMainApp(); + AAPSMocker.mockConfigBuilder(); + AAPSMocker.mockBus(); + AAPSMocker.mockStrings(); + AAPSMocker.mockApplicationContext(); + AAPSMocker.mockSP(); + + when(SP.getString(R.string.key_danars_address, "")).thenReturn(""); + + danaRPlugin = DanaRPlugin.getPlugin(); + } +} diff --git a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintTest.java b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintTest.java index 01c3a927f7..23352a57f9 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintTest.java +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintTest.java @@ -18,26 +18,33 @@ public class ConstraintTest { Constraint b = new Constraint<>(true); Assert.assertEquals(Boolean.TRUE, b.value()); Assert.assertEquals("", b.getReasons()); + Assert.assertEquals("", b.getMostLimitedReasons()); b.set(false); Assert.assertEquals(Boolean.FALSE, b.value()); Assert.assertEquals("", b.getReasons()); + Assert.assertEquals("", b.getMostLimitedReasons()); b.set(true, "Set true", this); Assert.assertEquals(Boolean.TRUE, b.value()); Assert.assertEquals("ConstraintTest: Set true", b.getReasons()); + Assert.assertEquals("ConstraintTest: Set true", b.getMostLimitedReasons()); b.set(false, "Set false", this); Assert.assertEquals(Boolean.FALSE, b.value()); Assert.assertEquals("ConstraintTest: Set true\nConstraintTest: Set false", b.getReasons()); + Assert.assertEquals("ConstraintTest: Set true\nConstraintTest: Set false", b.getMostLimitedReasons()); Constraint d = new Constraint<>(10d); d.set(5d, "Set 5d", this); Assert.assertEquals(5d, d.value()); Assert.assertEquals("ConstraintTest: Set 5d", d.getReasons()); + Assert.assertEquals("ConstraintTest: Set 5d", d.getMostLimitedReasons()); d.setIfSmaller(6d, "Set 6d", this); Assert.assertEquals(5d, d.value()); Assert.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d", d.getReasons()); + Assert.assertEquals("ConstraintTest: Set 5d", d.getMostLimitedReasons()); d.setIfSmaller(4d, "Set 4d", this); Assert.assertEquals(4d, d.value()); Assert.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d\nConstraintTest: Set 4d", d.getReasons()); + Assert.assertEquals("ConstraintTest: Set 4d", d.getMostLimitedReasons()); Assert.assertEquals(10d, d.originalValue()); } } diff --git a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.java b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.java index fc721d7173..65e949c83c 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.java +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.java @@ -7,7 +7,6 @@ import com.squareup.otto.Bus; import junit.framework.Assert; import org.json.JSONException; -import org.json.JSONObject; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -17,13 +16,11 @@ import org.powermock.modules.junit4.PowerMockRunner; import java.util.ArrayList; import java.util.Date; -import java.util.Locale; -import info.nightscout.androidaps.Constants; +import info.AAPSMocker; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.ConstraintChecker; -import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; @@ -40,7 +37,6 @@ import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.SP; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** @@ -50,16 +46,9 @@ import static org.mockito.Mockito.when; @PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, FabricPrivacy.class, SP.class, Context.class, OpenAPSMAPlugin.class, OpenAPSAMAPlugin.class, OpenAPSSMBPlugin.class}) public class ConstraintsCheckerTest { - PumpInterface pump = new VirtualPumpPlugin(); + VirtualPumpPlugin pump = new VirtualPumpPlugin(); ConstraintChecker constraintChecker; - ConfigBuilderPlugin configBuilderPlugin = mock(ConfigBuilderPlugin.class); - MainApp mainApp = mock(MainApp.class); - MockedBus bus = new MockedBus(); - - String validProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"},{\"time\":\"2:00\",\"value\":\"110\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"; - Profile profile = new Profile(new JSONObject(validProfile), Constants.MGDL); - SafetyPlugin safetyPlugin; ObjectivesPlugin objectivesPlugin; ComboPlugin comboPlugin; @@ -72,112 +61,63 @@ public class ConstraintsCheckerTest { public ConstraintsCheckerTest() throws JSONException { } - // isLoopInvokationAllowed tests @Test - public void pumpDescriptionShouldLimitLoopInvokation() throws Exception { - pump.getPumpDescription().isTempBasalCapable = false; - - Constraint c = constraintChecker.isLoopInvokationAllowed(); - Assert.assertEquals(true, c.getReasons().contains("Pump is not temp basal capable")); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - @Test - public void notStartedObjectivesShouldLimitLoopInvokation() throws Exception { - objectivesPlugin.objectives.get(0).setStarted(new Date(0)); - - Constraint c = constraintChecker.isLoopInvokationAllowed(); - Assert.assertEquals(true, c.getReasons().contains("Objective 1 not started")); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - @Test - public void invalidBasalRateOnComboPumpShouldLimitLoopInvokation() throws Exception { + public void isLoopInvokationAllowedTest() throws Exception { comboPlugin.setFragmentEnabled(PluginBase.PUMP, true); comboPlugin.setValidBasalRateProfileSelectedOnPump(false); Constraint c = constraintChecker.isLoopInvokationAllowed(); - Assert.assertEquals(true, c.getReasons().contains("No valid basal rate read from pump")); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - // isClosedLoopAllowed tests - @Test - public void disabledEngineeringModeShouldLimitClosedLoop() throws Exception { - when(SP.getString("aps_mode", "open")).thenReturn("closed"); - when(MainApp.isEngineeringModeOrRelease()).thenReturn(false); - - Constraint c = constraintChecker.isClosedLoopAllowed(); - Assert.assertEquals(true, c.getReasons().contains("Running dev version. Closed loop is disabled.")); + Assert.assertEquals(true, c.getReasonList().size() == 2); // Combo & Objectives + Assert.assertEquals(true, c.getMostLimitedReasonList().size() == 2); // Combo & Objectives Assert.assertEquals(Boolean.FALSE, c.value()); } @Test - public void setOpenLoopInPreferencesShouldLimitClosedLoop() throws Exception { - when(SP.getString("aps_mode", "open")).thenReturn("open"); - - Constraint c = constraintChecker.isClosedLoopAllowed(); - Assert.assertEquals(true, c.getReasons().contains("Closed loop mode disabled in preferences")); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - @Test - public void notStartedObjective4ShouldLimitClosedLoop() throws Exception { + public void isClosedLoopAllowedTest() throws Exception { when(SP.getString("aps_mode", "open")).thenReturn("closed"); objectivesPlugin.objectives.get(3).setStarted(new Date(0)); Constraint c = constraintChecker.isClosedLoopAllowed(); - Assert.assertEquals(true, c.getReasons().contains("Objective 4 not started")); + Assert.assertEquals(true, c.getReasonList().size() == 2); // Safety & Objectives + Assert.assertEquals(true, c.getMostLimitedReasonList().size() == 2); // Safety & Objectives + Assert.assertEquals(Boolean.FALSE, c.value()); + + when(SP.getString("aps_mode", "open")).thenReturn("open"); + c = constraintChecker.isClosedLoopAllowed(); + Assert.assertEquals(true, c.getReasonList().size() == 3); // 2x Safety & Objectives + Assert.assertEquals(true, c.getMostLimitedReasonList().size() == 3); // 2x Safety & Objectives Assert.assertEquals(Boolean.FALSE, c.value()); } - // isAutosensModeEnabled tests @Test - public void notStartedObjective6ShouldLimitAutosensMode() throws Exception { - objectivesPlugin.objectives.get(5).setStarted(new Date(0)); - - Constraint c = constraintChecker.isAutosensModeEnabled(); - Assert.assertEquals(true, c.getReasons().contains("Objective 6 not started")); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - // isAutosensModeEnabled tests - @Test - public void notEnabledAutosensInPreferencesDisablesAutosens() throws Exception { + public void isAutosensModeEnabledTest() throws Exception { objectivesPlugin.objectives.get(5).setStarted(new Date(0)); when(SP.getBoolean(R.string.key_openapsama_useautosens, false)).thenReturn(false); Constraint c = constraintChecker.isAutosensModeEnabled(); - Assert.assertEquals(true, c.getReasons().contains("Autosens disabled in preferences")); - Assert.assertEquals(true, c.getReasons().contains("Objective 6 not started")); + Assert.assertEquals(true, c.getReasonList().size() == 2); // Safety & Objectives + Assert.assertEquals(true, c.getMostLimitedReasonList().size() == 2); // Safety & Objectives Assert.assertEquals(Boolean.FALSE, c.value()); } @Test - public void notStartedObjective7ShouldLimitAMAMode() throws Exception { + public void isAMAModeEnabledTest() throws Exception { objectivesPlugin.objectives.get(6).setStarted(new Date(0)); Constraint c = constraintChecker.isAMAModeEnabled(); - Assert.assertEquals(true, c.getReasons().contains("Objective 7 not started")); + Assert.assertEquals(true, c.getReasonList().size() == 1); // Objectives + Assert.assertEquals(true, c.getMostLimitedReasonList().size() == 1); // Objectives Assert.assertEquals(Boolean.FALSE, c.value()); } - // isSMBModeEnabled tests @Test - public void notEnabledSMBInPreferencesDisablesSMB() throws Exception { + public void isSMBModeEnabledTest() throws Exception { + objectivesPlugin.objectives.get(7).setStarted(new Date(0)); when(SP.getBoolean(R.string.key_use_smb, false)).thenReturn(false); Constraint c = constraintChecker.isSMBModeEnabled(); - Assert.assertEquals(true, c.getReasons().contains("SMB disabled in preferences")); - Assert.assertEquals(Boolean.FALSE, c.value()); - } - - @Test - public void notStartedObjective8ShouldLimitSMBMode() throws Exception { - objectivesPlugin.objectives.get(7).setStarted(new Date(0)); - - Constraint c = constraintChecker.isSMBModeEnabled(); - Assert.assertEquals(true, c.getReasons().contains("Objective 8 not started")); + Assert.assertEquals(true, c.getReasonList().size() == 2); // Safety & Objectives + Assert.assertEquals(true, c.getMostLimitedReasonList().size() == 2); // Safety & Objectives Assert.assertEquals(Boolean.FALSE, c.value()); } @@ -195,33 +135,20 @@ public class ConstraintsCheckerTest { result.maximumBasalAmount = 1.1d; insightPlugin.setStatusResult(result); - // 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"); - // Negative basal not allowed - Constraint d = new Constraint<>(-0.5d); - constraintChecker.applyBasalConstraints(d, profile); - Assert.assertEquals(0d, d.value()); - Assert.assertEquals("SafetyPlugin: Limiting basal rate to 0.00 U/h because of it must be positive value", d.getReasons()); - // Apply all limits - d = constraintChecker.getMaxBasalAllowed(profile); + Constraint d = constraintChecker.getMaxBasalAllowed(AAPSMocker.getValidProfile()); Assert.assertEquals(0.8d, d.value()); - Assert.assertEquals("SafetyPlugin: Limiting basal rate to 1.00 U/h because of max value in preferences\n" + - "SafetyPlugin: Limiting basal rate to 4.00 U/h because of max basal multiplier\n" + - "SafetyPlugin: Limiting basal rate to 3.00 U/h because of max daily basal multiplier\n" + - "SafetyPlugin: Limiting basal rate to 2.00 U/h because of hard limit\n" + - "DanaRPlugin: Limiting basal rate to 0.80 U/h because of pump limit\n" + - "DanaRSPlugin: Limiting basal rate to 0.80 U/h because of pump limit\n" + - "InsightPumpPlugin: Limiting basal rate to 1.10 U/h because of pump limit", d.getReasons()); + Assert.assertEquals(true, d.getReasonList().size() == 7); // 4x Safety & RS & R & Insight + Assert.assertEquals("DanaR: Limiting basal rate to 0.80 U/h because of pump limit", d.getMostLimitedReasons()); } - // applyBasalConstraints tests @Test public void percentBasalRateShouldBeLimited() throws Exception { // DanaR, RS @@ -235,36 +162,17 @@ public class ConstraintsCheckerTest { result.maximumBasalAmount = 1.1d; insightPlugin.setStatusResult(result); - // 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"); - // Negative basal not allowed - Constraint i = new Constraint<>(-22); - constraintChecker.applyBasalPercentConstraints(i, profile); - Assert.assertEquals((Integer)0, i.value()); - Assert.assertEquals("SafetyPlugin: Percent rate -22% recalculated to -0.22 U/h with current basal 1.00 U/h\n" + - "SafetyPlugin: Limiting basal rate to 0.00 U/h because of it must be positive value\n" + - "SafetyPlugin: Limiting percent rate to 0% because of pump limit\n" + - "DanaRPlugin: Limiting percent rate to 0% because of it must be positive value\n" + - "DanaRSPlugin: Limiting percent rate to 0% because of it must be positive value\n" + - "InsightPumpPlugin: Limiting percent rate to 0% because of it must be positive value", i.getReasons()); - // Apply all limits - i = constraintChecker.getMaxBasalPercentAllowed(profile); - Assert.assertEquals((Integer)100, i.value()); - Assert.assertEquals("SafetyPlugin: Percent rate 1111111% recalculated to 11111.11 U/h with current basal 1.00 U/h\n" + - "SafetyPlugin: Limiting basal rate to 1.00 U/h because of max value in preferences\n" + - "SafetyPlugin: Limiting basal rate to 4.00 U/h because of max basal multiplier\n" + - "SafetyPlugin: Limiting basal rate to 3.00 U/h because of max daily basal multiplier\n" + - "SafetyPlugin: Limiting basal rate to 2.00 U/h because of hard limit\n" + - "SafetyPlugin: Limiting percent rate to 100% because of pump limit\n" + - "DanaRPlugin: Limiting percent rate to 200% because of pump limit\n" + - "DanaRSPlugin: Limiting percent rate to 200% because of pump limit\n" + - "InsightPumpPlugin: Limiting percent rate to 250% because of pump limit", i.getReasons()); + Constraint i = constraintChecker.getMaxBasalPercentAllowed(AAPSMocker.getValidProfile()); + Assert.assertEquals((Integer) 100, i.value()); + Assert.assertEquals(true, i.getReasonList().size() == 9); // 6x Safety & RS & R & Insight + Assert.assertEquals("Safety: Limiting percent rate to 100% because of pump limit", i.getMostLimitedReasons()); } @@ -282,25 +190,15 @@ public class ConstraintsCheckerTest { result.maximumBolusAmount = 7d; insightPlugin.setStatusResult(result); - // No limit by default when(SP.getDouble(R.string.key_treatmentssafety_maxbolus, 3d)).thenReturn(3d); when(SP.getString(R.string.key_age, "")).thenReturn("child"); - // Negative bolus not allowed - Constraint d = new Constraint<>(-22d); - constraintChecker.applyBolusConstraints(d); - Assert.assertEquals(0d, d.value()); - Assert.assertEquals("SafetyPlugin: Limiting bolus to 0.0 U because of it must be positive value", d.getReasons()); - // Apply all limits - d = constraintChecker.getMaxBolusAllowed(); + Constraint d = constraintChecker.getMaxBolusAllowed(); Assert.assertEquals(3d, d.value()); - Assert.assertEquals("SafetyPlugin: Limiting bolus to 3.0 U because of max value in preferences\n" + - "SafetyPlugin: Limiting bolus to 5.0 U because of hard limit\n" + - "DanaRPlugin: Limiting bolus to 6.0 U because of pump limit\n" + - "DanaRSPlugin: Limiting bolus to 6.0 U because of pump limit\n" + - "InsightPumpPlugin: Limiting bolus to 7.0 U because of pump limit", d.getReasons()); + Assert.assertEquals(true, d.getReasonList().size() == 5); // 2x Safety & RS & R & Insight + Assert.assertEquals("Safety: Limiting bolus to 3.0 U because of max value in preferences", d.getMostLimitedReasons()); } @@ -310,33 +208,16 @@ public class ConstraintsCheckerTest { // No limit by default when(SP.getInt(R.string.key_treatmentssafety_maxcarbs, 48)).thenReturn(48); - // Negative carbs not allowed - Constraint i = new Constraint<>(-22); - constraintChecker.applyCarbsConstraints(i); - Assert.assertEquals((Integer) 0, i.value()); - Assert.assertEquals("SafetyPlugin: Limiting carbs to 0 g because of it must be positive value", i.getReasons()); - // Apply all limits - i = constraintChecker.getMaxCarbsAllowed(); + Constraint i = constraintChecker.getMaxCarbsAllowed(); Assert.assertEquals((Integer) 48, i.value()); - Assert.assertEquals("SafetyPlugin: Limiting carbs to 48 g because of max value in preferences", i.getReasons()); + Assert.assertEquals(true, i.getReasonList().size() == 1); + Assert.assertEquals("Safety: Limiting carbs to 48 g because of max value in preferences", i.getMostLimitedReasons()); } // applyMaxIOBConstraints tests @Test public void iobShouldBeLimited() throws Exception { - // DanaR, RS - danaRPlugin.setFragmentEnabled(PluginBase.PUMP, true); - danaRSPlugin.setFragmentEnabled(PluginBase.PUMP, true); - DanaRPump.getInstance().maxBolus = 6d; - - // Insight - insightPlugin.setFragmentEnabled(PluginBase.PUMP, true); - StatusTaskRunner.Result result = new StatusTaskRunner.Result(); - result.maximumBolusAmount = 7d; - insightPlugin.setStatusResult(result); - - // No limit by default when(SP.getDouble(R.string.key_openapsma_max_iob, 1.5d)).thenReturn(1.5d); when(SP.getString(R.string.key_age, "")).thenReturn("teenage"); @@ -347,62 +228,31 @@ public class ConstraintsCheckerTest { // Apply all limits Constraint d = constraintChecker.getMaxIOBAllowed(); Assert.assertEquals(1.5d, d.value()); - Assert.assertEquals("SafetyPlugin: Limiting IOB to 1.5 U because of max value in preferences\n" + - "SafetyPlugin: Limiting IOB to 7.0 U because of hard limit\n" + - "SafetyPlugin: Limiting IOB to 7.0 U because of hard limit\n" + - "SafetyPlugin: Limiting IOB to 12.0 U because of hard limit", d.getReasons()); + Assert.assertEquals(true, d.getReasonList().size() == 4); + Assert.assertEquals("Safety: Limiting IOB to 1.5 U because of max value in preferences", d.getMostLimitedReasons()); } @Before public void prepareMock() throws Exception { - Locale.setDefault(new Locale("en", "US")); - PowerMockito.mockStatic(ConfigBuilderPlugin.class); - - PowerMockito.mockStatic(MainApp.class); - when(MainApp.instance()).thenReturn(mainApp); - when(MainApp.getConfigBuilder()).thenReturn(configBuilderPlugin); - when(MainApp.getConfigBuilder().getActivePump()).thenReturn(pump); - - constraintChecker = new ConstraintChecker(mainApp); PowerMockito.mockStatic(FabricPrivacy.class); - Context context = mock(Context.class); - when(MainApp.instance().getApplicationContext()).thenReturn(context); + MainApp mainApp = AAPSMocker.mockMainApp(); + AAPSMocker.mockConfigBuilder(); + AAPSMocker.mockApplicationContext(); + AAPSMocker.mockBus(); + AAPSMocker.mockStrings(); + AAPSMocker.mockSP(); - when(MainApp.bus()).thenReturn(bus); - - when(MainApp.gs(R.string.pumpisnottempbasalcapable)).thenReturn("Pump is not temp basal capable"); - when(MainApp.gs(R.string.closed_loop_disabled_on_dev_branch)).thenReturn("Running dev version. Closed loop is disabled."); - when(MainApp.gs(R.string.closedmodedisabledinpreferences)).thenReturn("Closed loop mode disabled in preferences"); - when(MainApp.gs(R.string.objectivenotstarted)).thenReturn("Objective %d not started"); - when(MainApp.gs(R.string.novalidbasalrate)).thenReturn("No valid basal rate read from pump"); - when(MainApp.gs(R.string.autosensdisabledinpreferences)).thenReturn("Autosens disabled in preferences"); - when(MainApp.gs(R.string.smbdisabledinpreferences)).thenReturn("SMB disabled in preferences"); - when(MainApp.gs(R.string.limitingbasalratio)).thenReturn("Limiting basal rate to %.2f U/h because of %s"); - when(MainApp.gs(R.string.pumplimit)).thenReturn("pump limit"); - when(MainApp.gs(R.string.itmustbepositivevalue)).thenReturn("it must be positive value"); - when(MainApp.gs(R.string.maxvalueinpreferences)).thenReturn("max value in preferences"); - when(MainApp.gs(R.string.maxbasalmultiplier)).thenReturn("max basal multiplier"); - when(MainApp.gs(R.string.maxdailybasalmultiplier)).thenReturn("max daily basal multiplier"); - when(MainApp.gs(R.string.limitingpercentrate)).thenReturn("Limiting percent rate to %d%% because of %s"); - when(MainApp.gs(R.string.pumplimit)).thenReturn("pump limit"); - when(MainApp.gs(R.string.limitingbolus)).thenReturn("Limiting bolus to %.1f U because of %s"); - when(MainApp.gs(R.string.hardlimit)).thenReturn("hard limit"); - when(MainApp.gs(R.string.key_child)).thenReturn("child"); - when(MainApp.gs(R.string.limitingcarbs)).thenReturn("Limiting carbs to %d g because of %s"); - when(MainApp.gs(R.string.limitingiob)).thenReturn("Limiting IOB to %.1f U because of %s"); - - PowerMockito.mockStatic(SP.class); - //PowerMockito.mock(OpenAPSMAPlugin.class); - //PowerMockito.mock(OpenAPSAMAPlugin.class); - //PowerMockito.mock(OpenAPSSMBPlugin.class); - - PowerMockito.mockStatic(SP.class); // RS constructor when(SP.getString(R.string.key_danars_address, "")).thenReturn(""); + //SafetyPlugin + when(MainApp.getConfigBuilder().getActivePump()).thenReturn(pump); + + constraintChecker = new ConstraintChecker(mainApp); + safetyPlugin = SafetyPlugin.getPlugin(); objectivesPlugin = ObjectivesPlugin.getPlugin(); comboPlugin = ComboPlugin.getPlugin(); diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/ConstraintsObjectives/ObjectivesPluginTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/ConstraintsObjectives/ObjectivesPluginTest.java new file mode 100644 index 0000000000..116fd3fee6 --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/ConstraintsObjectives/ObjectivesPluginTest.java @@ -0,0 +1,90 @@ +package info.nightscout.androidaps.plugins.ConstraintsObjectives; + +import junit.framework.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 java.util.Date; + +import info.AAPSMocker; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.interfaces.Constraint; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.utils.SP; + +/** + * Created by mike on 23.03.2018. + */ + +@RunWith(PowerMockRunner.class) +@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, SP.class}) +public class ObjectivesPluginTest { + + ObjectivesPlugin objectivesPlugin; + + @Test + public void notStartedObjectivesShouldLimitLoopInvokation() throws Exception { + objectivesPlugin.objectives.get(0).setStarted(new Date(0)); + + Constraint c = new Constraint<>(true); + c = objectivesPlugin.isLoopInvokationAllowed(c); + Assert.assertEquals("Objectives: Objective 1 not started", c.getReasons()); + Assert.assertEquals(Boolean.FALSE, c.value()); + objectivesPlugin.objectives.get(0).setStarted(new Date()); + } + + @Test + public void notStartedObjective4ShouldLimitClosedLoop() throws Exception { + objectivesPlugin.objectives.get(3).setStarted(new Date(0)); + + Constraint c = new Constraint<>(true); + c = objectivesPlugin.isClosedLoopAllowed(c); + Assert.assertEquals(true, c.getReasons().contains("Objective 4 not started")); + Assert.assertEquals(Boolean.FALSE, c.value()); + } + + @Test + public void notStartedObjective6ShouldLimitAutosensMode() throws Exception { + objectivesPlugin.objectives.get(5).setStarted(new Date(0)); + + Constraint c = new Constraint<>(true); + c = objectivesPlugin.isAutosensModeEnabled(c); + Assert.assertEquals(true, c.getReasons().contains("Objective 6 not started")); + Assert.assertEquals(Boolean.FALSE, c.value()); + } + + @Test + public void notStartedObjective7ShouldLimitAMAMode() throws Exception { + objectivesPlugin.objectives.get(6).setStarted(new Date(0)); + + Constraint c = new Constraint<>(true); + c = objectivesPlugin.isAMAModeEnabled(c); + Assert.assertEquals(true, c.getReasons().contains("Objective 7 not started")); + Assert.assertEquals(Boolean.FALSE, c.value()); + } + + @Test + public void notStartedObjective8ShouldLimitSMBMode() throws Exception { + objectivesPlugin.objectives.get(7).setStarted(new Date(0)); + + Constraint c = new Constraint<>(true); + c = objectivesPlugin.isSMBModeEnabled(c); + Assert.assertEquals(true, c.getReasons().contains("Objective 8 not started")); + Assert.assertEquals(Boolean.FALSE, c.value()); + } + + @Before + public void prepareMock() { + AAPSMocker.mockMainApp(); + AAPSMocker.mockConfigBuilder(); + AAPSMocker.mockBus(); + AAPSMocker.mockSP(); + AAPSMocker.mockStrings(); + + objectivesPlugin = ObjectivesPlugin.getPlugin(); + } +} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPluginTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPluginTest.java new file mode 100644 index 0000000000..c88f60fd92 --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/ConstraintsSafety/SafetyPluginTest.java @@ -0,0 +1,214 @@ +package info.nightscout.androidaps.plugins.ConstraintsSafety; + +import android.content.Context; + +import junit.framework.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.PluginBase; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin; +import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin; +import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin; +import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; +import info.nightscout.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}) +public class SafetyPluginTest { + + VirtualPumpPlugin pump = new VirtualPumpPlugin(); + SafetyPlugin safetyPlugin; + + @Test + public void pumpDescriptionShouldLimitLoopInvokation() throws Exception { + pump.getPumpDescription().isTempBasalCapable = false; + + Constraint c = new Constraint<>(true); + c = safetyPlugin.isLoopInvokationAllowed(c); + Assert.assertEquals("Safety: Pump is not temp basal capable", c.getReasons()); + Assert.assertEquals(Boolean.FALSE, c.value()); + } + + @Test + public void disabledEngineeringModeShouldLimitClosedLoop() throws Exception { + when(SP.getString("aps_mode", "open")).thenReturn("closed"); + when(MainApp.isEngineeringModeOrRelease()).thenReturn(false); + + Constraint c = new Constraint<>(true); + c = safetyPlugin.isClosedLoopAllowed(c); + Assert.assertEquals(true, c.getReasons().contains("Running dev version. Closed loop is disabled.")); + Assert.assertEquals(Boolean.FALSE, c.value()); + } + + @Test + public void setOpenLoopInPreferencesShouldLimitClosedLoop() throws Exception { + when(SP.getString("aps_mode", "open")).thenReturn("open"); + + Constraint c = new Constraint<>(true); + c = safetyPlugin.isClosedLoopAllowed(c); + Assert.assertEquals(true, c.getReasons().contains("Closed loop mode disabled in preferences")); + Assert.assertEquals(Boolean.FALSE, c.value()); + } + + @Test + public void notEnabledSMBInPreferencesDisablesSMB() throws Exception { + when(SP.getBoolean(R.string.key_use_smb, false)).thenReturn(false); + + Constraint c = new Constraint<>(true); + c = safetyPlugin.isSMBModeEnabled(c); + Assert.assertEquals(true, c.getReasons().contains("SMB disabled in preferences")); + Assert.assertEquals(Boolean.FALSE, c.value()); + } + + @Test + public void basalRateShouldBeLimited() throws Exception { + 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()); + 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() throws Exception { + 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()); + Assert.assertEquals("Safety: Limiting basal rate to 0.00 U/h because of it must be positive value", d.getReasons()); + } + + @Test + public void percentBasalRateShouldBeLimited() throws Exception { + // 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() throws Exception { + 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: 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() throws Exception { + 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()); + 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() throws Exception { + 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()); + 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() throws Exception { + // 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() throws Exception { + 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().setFragmentEnabled(PluginBase.APS, true); + OpenAPSAMAPlugin.getPlugin().setFragmentEnabled(PluginBase.APS, true); + OpenAPSSMBPlugin.getPlugin().setFragmentEnabled(PluginBase.APS, true); + + // Apply all limits + Constraint d = new Constraint<>(Constants.REALLYHIGHIOB); + d = safetyPlugin.applyMaxIOBConstraints(d); + Assert.assertEquals(1.5d, d.value()); + 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\n" + + "Safety: Limiting IOB to 12.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.mockSP(); + AAPSMocker.mockStrings(); + + when(MainApp.getConfigBuilder().getActivePump()).thenReturn(pump); + + safetyPlugin = SafetyPlugin.getPlugin(); + } +} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPluginTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPluginTest.java index a87cbbfbd4..05e3e58866 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPluginTest.java +++ b/app/src/test/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPluginTest.java @@ -2,62 +2,68 @@ package info.nightscout.androidaps.plugins.PumpCombo; import android.content.Context; -import com.squareup.otto.Bus; -import com.squareup.otto.ThreadEnforcer; - import org.junit.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 info.AAPSMocker; import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.interfaces.Constraint; +import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.Bolus; import info.nightscout.utils.ToastUtils; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; @RunWith(PowerMockRunner.class) -@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class}) +@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class}) public class ComboPluginTest { - @Before - public void prepareMocks() throws Exception { - ConfigBuilderPlugin configBuilderPlugin = mock(ConfigBuilderPlugin.class); - PowerMockito.mockStatic(ConfigBuilderPlugin.class); + ComboPlugin comboPlugin; - PowerMockito.mockStatic(MainApp.class); - MainApp mainApp = mock(MainApp.class); - when(MainApp.getConfigBuilder()).thenReturn(configBuilderPlugin); - when(MainApp.instance()).thenReturn(mainApp); - Bus bus = new Bus(ThreadEnforcer.ANY); - when(MainApp.bus()).thenReturn(bus); - when(MainApp.gs(0)).thenReturn(""); + @Test + public void invalidBasalRateOnComboPumpShouldLimitLoopInvokation() throws Exception { + comboPlugin.setFragmentEnabled(PluginBase.PUMP, true); + comboPlugin.setValidBasalRateProfileSelectedOnPump(false); + + Constraint c = new Constraint<>(true); + c = comboPlugin.isLoopInvokationAllowed(c); + Assert.assertEquals("Combo: No valid basal rate read from pump", c.getReasons()); + Assert.assertEquals(Boolean.FALSE, c.value()); + comboPlugin.setFragmentEnabled(PluginBase.PUMP, false); } @Test public void calculateFakePumpTimestamp() throws Exception { - ComboPlugin plugin = ComboPlugin.getPlugin(); long now = System.currentTimeMillis(); long pumpTimestamp = now - now % 1000; // same timestamp, different bolus leads to different fake timestamp Assert.assertNotEquals( - plugin.calculateFakeBolusDate(new Bolus(pumpTimestamp, 0.1, true)), - plugin.calculateFakeBolusDate(new Bolus(pumpTimestamp, 0.3, true)) + comboPlugin.calculateFakeBolusDate(new Bolus(pumpTimestamp, 0.1, true)), + comboPlugin.calculateFakeBolusDate(new Bolus(pumpTimestamp, 0.3, true)) ); // different timestamp, same bolus leads to different fake timestamp Assert.assertNotEquals( - plugin.calculateFakeBolusDate(new Bolus(pumpTimestamp, 0.3, true)), - plugin.calculateFakeBolusDate(new Bolus(pumpTimestamp + 60 * 1000, 0.3, true)) + comboPlugin.calculateFakeBolusDate(new Bolus(pumpTimestamp, 0.3, true)), + comboPlugin.calculateFakeBolusDate(new Bolus(pumpTimestamp + 60 * 1000, 0.3, true)) ); // generated timestamp has second-precision Bolus bolus = new Bolus(pumpTimestamp, 0.2, true); - long calculatedTimestamp = plugin.calculateFakeBolusDate(bolus); + long calculatedTimestamp = comboPlugin.calculateFakeBolusDate(bolus); assertEquals(calculatedTimestamp, calculatedTimestamp - calculatedTimestamp % 1000); } + + @Before + public void prepareMocks() throws Exception { + AAPSMocker.mockMainApp(); + AAPSMocker.mockConfigBuilder(); + AAPSMocker.mockBus(); + AAPSMocker.mockStrings(); + + comboPlugin = ComboPlugin.getPlugin(); + } } \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPluginTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPluginTest.java new file mode 100644 index 0000000000..837298fe1d --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPluginTest.java @@ -0,0 +1,75 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS; + +import android.content.Context; + +import junit.framework.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.PluginBase; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; +import info.nightscout.utils.SP; +import info.nightscout.utils.ToastUtils; + +import static org.mockito.Mockito.when; + +/** + * Created by mike on 23.03.2018. + */ + +@RunWith(PowerMockRunner.class) +@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class, SP.class}) +public class DanaRSPluginTest { + + DanaRSPlugin danaRSPlugin; + + @Test + public void basalRateShouldBeLimited() throws Exception { + danaRSPlugin.setFragmentEnabled(PluginBase.PUMP, true); + danaRSPlugin.setFragmentEnabled(PluginBase.PUMP, true); + DanaRPump.getInstance().maxBasal = 0.8d; + + Constraint c = new Constraint<>(Constants.REALLYHIGHBASALRATE); + danaRSPlugin.applyBasalConstraints(c, AAPSMocker.getValidProfile()); + Assert.assertEquals(0.8d, c.value()); + Assert.assertEquals("DanaRS: Limiting basal rate to 0.80 U/h because of pump limit", c.getReasons()); + Assert.assertEquals("DanaRS: Limiting basal rate to 0.80 U/h because of pump limit", c.getMostLimitedReasons()); + } + + @Test + public void percentBasalRateShouldBeLimited() throws Exception { + danaRSPlugin.setFragmentEnabled(PluginBase.PUMP, true); + danaRSPlugin.setFragmentEnabled(PluginBase.PUMP, true); + DanaRPump.getInstance().maxBasal = 0.8d; + + Constraint c = new Constraint<>(Constants.REALLYHIGHPERCENTBASALRATE); + danaRSPlugin.applyBasalPercentConstraints(c, AAPSMocker.getValidProfile()); + Assert.assertEquals((Integer) 200, c.value()); + Assert.assertEquals("DanaRS: Limiting percent rate to 200% because of pump limit", c.getReasons()); + Assert.assertEquals("DanaRS: Limiting percent rate to 200% because of pump limit", c.getMostLimitedReasons()); + } + + @Before + public void prepareMocks() throws Exception { + AAPSMocker.mockMainApp(); + AAPSMocker.mockConfigBuilder(); + AAPSMocker.mockBus(); + AAPSMocker.mockStrings(); + AAPSMocker.mockApplicationContext(); + AAPSMocker.mockSP(); + + when(SP.getString(R.string.key_danars_address, "")).thenReturn(""); + + danaRSPlugin = DanaRSPlugin.getPlugin(); + } +} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/PumpInsight/PumpInsightTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/PumpInsight/PumpInsightTest.java new file mode 100644 index 0000000000..e8481f64ef --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/PumpInsight/PumpInsightTest.java @@ -0,0 +1,56 @@ +package info.nightscout.androidaps.plugins.PumpInsight; + +import android.content.Context; + +import junit.framework.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.interfaces.Constraint; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.PumpInsight.connector.StatusTaskRunner; +import info.nightscout.utils.ToastUtils; + +/** + * Created by mike on 23.03.2018. + */ + +@RunWith(PowerMockRunner.class) +@PrepareForTest({MainApp.class, ConfigBuilderPlugin.class, ToastUtils.class, Context.class}) +public class PumpInsightTest { + + InsightPumpPlugin insightPlugin; + + @Test + public void basalRateShouldBeLimited() throws Exception { + insightPlugin.setFragmentEnabled(PluginBase.PUMP, true); + StatusTaskRunner.Result result = new StatusTaskRunner.Result(); + result.maximumBasalAmount = 1.1d; + insightPlugin.setStatusResult(result); + + Constraint c = new Constraint<>(Constants.REALLYHIGHBASALRATE); + insightPlugin.applyBasalConstraints(c, AAPSMocker.getValidProfile()); + Assert.assertEquals(1.1d, c.value()); + Assert.assertEquals("InsightPump: Limiting basal rate to 1.10 U/h because of pump limit", c.getReasons()); + Assert.assertEquals("InsightPump: Limiting basal rate to 1.10 U/h because of pump limit", c.getMostLimitedReasons()); + } + + @Before + public void prepareMocks() throws Exception { + AAPSMocker.mockMainApp(); + AAPSMocker.mockConfigBuilder(); + AAPSMocker.mockBus(); + AAPSMocker.mockStrings(); + + insightPlugin = InsightPumpPlugin.getPlugin(); + } + +}