diff --git a/database/entities/src/main/java/info/nightscout/database/entities/ProfileSwitch.kt b/database/entities/src/main/java/info/nightscout/database/entities/ProfileSwitch.kt index ed541a3c7a..9aced1b0b3 100644 --- a/database/entities/src/main/java/info/nightscout/database/entities/ProfileSwitch.kt +++ b/database/entities/src/main/java/info/nightscout/database/entities/ProfileSwitch.kt @@ -52,7 +52,25 @@ data class ProfileSwitch( var insulinConfiguration: InsulinConfiguration ) : TraceableDBEntry, DBEntryWithTimeAndDuration { - private fun contentEqualsTo(other: ProfileSwitch): Boolean = + fun copy(): ProfileSwitch = + ProfileSwitch( + isValid = isValid, + timestamp = timestamp, + utcOffset = utcOffset, + basalBlocks = basalBlocks, + isfBlocks = isfBlocks, + icBlocks = icBlocks, + targetBlocks = targetBlocks, + glucoseUnit = glucoseUnit, + profileName = profileName, + timeshift = timeshift, + percentage = percentage, + duration = duration, + insulinConfiguration = insulinConfiguration, + interfaceIDs_backing = interfaceIDs_backing + ) + + fun contentEqualsTo(other: ProfileSwitch): Boolean = isValid == other.isValid && timestamp == other.timestamp && utcOffset == other.utcOffset && diff --git a/plugins/sync/build.gradle b/plugins/sync/build.gradle index ef7c42eec7..17613b56ae 100644 --- a/plugins/sync/build.gradle +++ b/plugins/sync/build.gradle @@ -26,6 +26,7 @@ dependencies { implementation project(':core:utils') implementation project(':core:validators') + testImplementation project(':implementation') // NSClient, Tidepool api("io.socket:socket.io-client:1.0.2") { diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/extensions/ProfileSwitchExtension.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/extensions/ProfileSwitchExtension.kt index 0d7e027ddb..fad17e37c0 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/extensions/ProfileSwitchExtension.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/extensions/ProfileSwitchExtension.kt @@ -41,23 +41,22 @@ fun NSProfileSwitch.toProfileSwitch(activePlugin: ActivePlugin, dateUtil: DateUt fun ProfileSwitch.toNSProfileSwitch(dateUtil: DateUtil): NSProfileSwitch { val unmodifiedCustomizedName = getCustomizedName() // ProfileSealed.PS doesn't provide unmodified json -> reset it - val unmodifiedTimeshift = timeshift - val unmodifiedPercentage = percentage - timeshift = 0 - percentage = 100 + val notCustomized = this.copy() + notCustomized.timeshift = 0 + notCustomized.percentage = 100 return NSProfileSwitch( eventType = EventType.fromString(TherapyEvent.Type.PROFILE_SWITCH.text), isValid = isValid, date = timestamp, utcOffset = utcOffset, - timeShift = unmodifiedTimeshift, - percentage = unmodifiedPercentage, + timeShift = timeshift, + percentage = percentage, duration = T.mins(duration).msecs(), profile = unmodifiedCustomizedName, originalProfileName = profileName, originalDuration = duration, - profileJson = ProfileSealed.PS(this).toPureNsJson(dateUtil), + profileJson = ProfileSealed.PS(notCustomized).toPureNsJson(dateUtil), identifier = interfaceIDs.nightscoutId, pumpId = interfaceIDs.pumpId, pumpType = interfaceIDs.pumpType?.name, diff --git a/plugins/sync/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt b/plugins/sync/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt new file mode 100644 index 0000000000..58e161ed76 --- /dev/null +++ b/plugins/sync/src/test/java/info/nightscout/androidaps/TestBaseWithProfile.kt @@ -0,0 +1,193 @@ +package info.nightscout.androidaps + +import android.content.Context +import dagger.android.AndroidInjector +import dagger.android.HasAndroidInjector +import info.nightscout.core.extensions.pureProfileFromJson +import info.nightscout.core.profile.ProfileSealed +import info.nightscout.core.utils.fabric.FabricPrivacy +import info.nightscout.database.entities.EffectiveProfileSwitch +import info.nightscout.database.entities.embedments.InsulinConfiguration +import info.nightscout.database.impl.AppRepository +import info.nightscout.implementation.profile.ProfileFunctionImpl +import info.nightscout.implementation.profile.ProfileStoreObject +import info.nightscout.interfaces.Config +import info.nightscout.interfaces.insulin.Insulin +import info.nightscout.interfaces.iob.IobCobCalculator +import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData +import info.nightscout.interfaces.plugin.ActivePlugin +import info.nightscout.interfaces.profile.ProfileFunction +import info.nightscout.interfaces.profile.ProfileStore +import info.nightscout.interfaces.utils.HardLimits +import info.nightscout.rx.bus.RxBus +import info.nightscout.shared.interfaces.ResourceHelper +import info.nightscout.shared.sharedPreferences.SP +import info.nightscout.shared.utils.DateUtil +import org.json.JSONObject +import org.junit.jupiter.api.BeforeEach +import org.mockito.ArgumentMatchers.anyDouble +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyString +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.`when` +import org.mockito.invocation.InvocationOnMock + +@Suppress("SpellCheckingInspection") +open class TestBaseWithProfile : TestBase() { + + @Mock lateinit var activePlugin: ActivePlugin + @Mock lateinit var rh: ResourceHelper + @Mock lateinit var iobCobCalculator: IobCobCalculator + @Mock lateinit var fabricPrivacy: FabricPrivacy + @Mock lateinit var config: Config + @Mock lateinit var context: Context + @Mock lateinit var sp: SP + @Mock lateinit var repository: AppRepository + @Mock lateinit var hardLimits: HardLimits + @Mock lateinit var processedDeviceStatusData: ProcessedDeviceStatusData + @Mock lateinit var insulin: Insulin + + lateinit var profileFunction: ProfileFunction + lateinit var dateUtil: DateUtil + var insulinConfiguration: InsulinConfiguration = InsulinConfiguration("Insulin", 360 * 60 * 1000, 60 * 60 * 1000) + val rxBus = RxBus(aapsSchedulers, aapsLogger) + + val profileInjector = HasAndroidInjector { AndroidInjector { } } + + private lateinit var validProfileJSON: String + lateinit var validProfile: ProfileSealed.Pure + lateinit var effectiveProfileSwitch: EffectiveProfileSwitch + + @Suppress("PropertyName") val TESTPROFILENAME = "someProfile" + + @BeforeEach + fun prepareMock() { + validProfileJSON = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," + + "{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," + + "\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}" + dateUtil = Mockito.spy(DateUtil(context)) + `when`(dateUtil.now()).thenReturn(1656358822000) + `when`(insulin.insulinConfiguration).thenReturn(insulinConfiguration) + `when`(activePlugin.activeInsulin).thenReturn(insulin) + profileFunction = ProfileFunctionImpl(aapsLogger, sp, rxBus, rh, activePlugin, repository, dateUtil, config, hardLimits, aapsSchedulers, fabricPrivacy, processedDeviceStatusData) + validProfile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(validProfileJSON), dateUtil)!!) + effectiveProfileSwitch = EffectiveProfileSwitch( + timestamp = dateUtil.now(), + basalBlocks = validProfile.basalBlocks, + isfBlocks = validProfile.isfBlocks, + icBlocks = validProfile.icBlocks, + targetBlocks = validProfile.targetBlocks, + glucoseUnit = EffectiveProfileSwitch.GlucoseUnit.MMOL, + originalProfileName = "", + originalCustomizedName = "", + originalTimeshift = 0, + originalPercentage = 100, + originalDuration = 0, + originalEnd = 0, + insulinConfiguration = InsulinConfiguration("", 0, 0) + ) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + String.format(rh.gs(string), arg1) + }.`when`(rh).gs(anyInt(), anyInt()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + String.format(rh.gs(string), arg1) + }.`when`(rh).gs(anyInt(), anyDouble()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + String.format(rh.gs(string), arg1) + }.`when`(rh).gs(anyInt(), anyString()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + val arg2 = invocation.getArgument(2) + String.format(rh.gs(string), arg1, arg2) + }.`when`(rh).gs(anyInt(), anyString(), anyString()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + val arg2 = invocation.getArgument(2) + String.format(rh.gs(string), arg1, arg2) + }.`when`(rh).gs(anyInt(), anyString(), anyInt()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + val arg2 = invocation.getArgument(2) + String.format(rh.gs(string), arg1, arg2) + }.`when`(rh).gs(anyInt(), anyDouble(), anyString()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + val arg2 = invocation.getArgument(2) + String.format(rh.gs(string), arg1, arg2) + }.`when`(rh).gs(anyInt(), anyDouble(), anyInt()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + val arg2 = invocation.getArgument(2) + String.format(rh.gs(string), arg1, arg2) + }.`when`(rh).gs(anyInt(), anyInt(), anyInt()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + val arg2 = invocation.getArgument(2) + String.format(rh.gs(string), arg1, arg2) + }.`when`(rh).gs(anyInt(), anyInt(), anyString()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + val arg2 = invocation.getArgument(2) + val arg3 = invocation.getArgument(3) + String.format(rh.gs(string), arg1, arg2, arg3) + }.`when`(rh).gs(anyInt(), anyInt(), anyInt(), anyString()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + val arg2 = invocation.getArgument(2) + val arg3 = invocation.getArgument(3) + String.format(rh.gs(string), arg1, arg2, arg3) + }.`when`(rh).gs(anyInt(), anyInt(), anyString(), anyString()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + val arg2 = invocation.getArgument(2) + val arg3 = invocation.getArgument(3) + String.format(rh.gs(string), arg1, arg2, arg3) + }.`when`(rh).gs(anyInt(), anyDouble(), anyInt(), anyString()) + + Mockito.doAnswer { invocation: InvocationOnMock -> + val string = invocation.getArgument(0) + val arg1 = invocation.getArgument(1) + val arg2 = invocation.getArgument(2) + val arg3 = invocation.getArgument(3) + String.format(rh.gs(string), arg1, arg2, arg3) + }.`when`(rh).gs(anyInt(), anyString(), anyInt(), anyString()) + + } + + fun getValidProfileStore(): ProfileStore { + val json = JSONObject() + val store = JSONObject() + store.put(TESTPROFILENAME, JSONObject(validProfileJSON)) + json.put("defaultProfile", TESTPROFILENAME) + json.put("store", store) + return ProfileStoreObject(profileInjector, json, dateUtil) + } +} diff --git a/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/extensions/ProfileSwitchExtensionKtTest.kt b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/extensions/ProfileSwitchExtensionKtTest.kt new file mode 100644 index 0000000000..839a512343 --- /dev/null +++ b/plugins/sync/src/test/java/info/nightscout/plugins/sync/nsclientV3/extensions/ProfileSwitchExtensionKtTest.kt @@ -0,0 +1,71 @@ +package info.nightscout.plugins.sync.nsclientV3.extensions + +import info.nightscout.androidaps.TestBaseWithProfile +import info.nightscout.core.extensions.fromConstant +import info.nightscout.database.entities.ProfileSwitch +import info.nightscout.database.entities.embedments.InterfaceIDs +import info.nightscout.sdk.localmodel.treatment.NSProfileSwitch +import info.nightscout.sdk.mapper.convertToRemoteAndBack +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +@Suppress("SpellCheckingInspection") +internal class ProfileSwitchExtensionKtTest : TestBaseWithProfile() { + + @Test + fun toProfileSwitch() { + var profileSwitch = ProfileSwitch( + timestamp = 10000, + isValid = true, + basalBlocks = validProfile.basalBlocks, + isfBlocks = validProfile.isfBlocks, + icBlocks = validProfile.icBlocks, + targetBlocks = validProfile.targetBlocks, + glucoseUnit = ProfileSwitch.GlucoseUnit.fromConstant(validProfile.units), + profileName = "SomeProfile", + timeshift = 0, + percentage = 100, + duration = 0, + insulinConfiguration = activePlugin.activeInsulin.insulinConfiguration.also { + it.insulinEndTime = (validProfile.dia * 3600 * 1000).toLong() + }, + interfaceIDs_backing = InterfaceIDs( + nightscoutId = "nightscoutId", + pumpId = 11000, + pumpType = InterfaceIDs.PumpType.DANA_I, + pumpSerial = "bbbb" + ) + ) + + var profileSwitch2 = (profileSwitch.toNSProfileSwitch(dateUtil).convertToRemoteAndBack() as NSProfileSwitch).toProfileSwitch(activePlugin, dateUtil)!! + Assertions.assertTrue(profileSwitch.contentEqualsTo(profileSwitch2)) + Assertions.assertTrue(profileSwitch.interfaceIdsEqualsTo(profileSwitch2)) + + profileSwitch = ProfileSwitch( + timestamp = 10000, + isValid = true, + basalBlocks = validProfile.basalBlocks, + isfBlocks = validProfile.isfBlocks, + icBlocks = validProfile.icBlocks, + targetBlocks = validProfile.targetBlocks, + glucoseUnit = ProfileSwitch.GlucoseUnit.fromConstant(validProfile.units), + profileName = "SomeProfile", + timeshift = -3600000, + percentage = 150, + duration = 3600000, + insulinConfiguration = activePlugin.activeInsulin.insulinConfiguration.also { + it.insulinEndTime = (validProfile.dia * 3600 * 1000).toLong() + }, + interfaceIDs_backing = InterfaceIDs( + nightscoutId = "nightscoutId", + pumpId = 11000, + pumpType = InterfaceIDs.PumpType.DANA_I, + pumpSerial = "bbbb" + ) + ) + + profileSwitch2 = (profileSwitch.toNSProfileSwitch(dateUtil).convertToRemoteAndBack() as NSProfileSwitch).toProfileSwitch(activePlugin, dateUtil)!! + Assertions.assertTrue(profileSwitch.contentEqualsTo(profileSwitch2)) + Assertions.assertTrue(profileSwitch.interfaceIdsEqualsTo(profileSwitch2)) + } +} \ No newline at end of file