diff --git a/app-wear-shared/shared-impl/build.gradle b/app-wear-shared/shared-impl/build.gradle index ff74d6e773..f2c115b890 100644 --- a/app-wear-shared/shared-impl/build.gradle +++ b/app-wear-shared/shared-impl/build.gradle @@ -8,6 +8,9 @@ plugins { apply from: "${project.rootDir}/core/main/android_dependencies.gradle" apply from: "${project.rootDir}/core/main/android_module_dependencies.gradle" +apply from: "${project.rootDir}/core/main/allopen_dependencies.gradle" +apply from: "${project.rootDir}/core/main/test_dependencies.gradle" +apply from: "${project.rootDir}/core/main/jacoco_global.gradle" android { diff --git a/app-wear-shared/shared-impl/src/main/java/info/nightscout/shared/impl/sharedPreferences/SPImplementation.kt b/app-wear-shared/shared-impl/src/main/java/info/nightscout/shared/impl/sharedPreferences/SPImplementation.kt index d53abb74e4..725406b1ea 100644 --- a/app-wear-shared/shared-impl/src/main/java/info/nightscout/shared/impl/sharedPreferences/SPImplementation.kt +++ b/app-wear-shared/shared-impl/src/main/java/info/nightscout/shared/impl/sharedPreferences/SPImplementation.kt @@ -27,6 +27,7 @@ class SPImplementation @Inject constructor( override fun remove(@StringRes resourceID: Int) { spEdit.remove(context.getString(resourceID)) } + override fun remove(key: String) { spEdit.remove(key) } @@ -34,30 +35,39 @@ class SPImplementation @Inject constructor( override fun putBoolean(key: String, value: Boolean) { spEdit.putBoolean(key, value) } + override fun putBoolean(@StringRes resourceID: Int, value: Boolean) { spEdit.putBoolean(context.getString(resourceID), value) } + override fun putDouble(key: String, value: Double) { spEdit.putString(key, value.toString()) } + override fun putDouble(@StringRes resourceID: Int, value: Double) { spEdit.putString(context.getString(resourceID), value.toString()) } + override fun putLong(key: String, value: Long) { spEdit.putLong(key, value) } + override fun putLong(@StringRes resourceID: Int, value: Long) { spEdit.putLong(context.getString(resourceID), value) } + override fun putInt(key: String, value: Int) { spEdit.putInt(key, value) } + override fun putInt(@StringRes resourceID: Int, value: Int) { spEdit.putInt(context.getString(resourceID), value) } + override fun putString(key: String, value: String) { spEdit.putString(key, value) } + override fun putString(@StringRes resourceID: Int, value: String) { spEdit.putString(context.getString(resourceID), value) } @@ -88,15 +98,15 @@ class SPImplementation @Inject constructor( override fun getString(resourceID: Int, defaultValue: String): String = sharedPreferences.getString(context.getString(resourceID), defaultValue) ?: defaultValue + override fun getString(key: String, defaultValue: String): String = + sharedPreferences.getString(key, defaultValue) ?: defaultValue + override fun getStringOrNull(resourceID: Int, defaultValue: String?): String? = sharedPreferences.getString(context.getString(resourceID), defaultValue) ?: defaultValue override fun getStringOrNull(key: String, defaultValue: String?): String? = sharedPreferences.getString(key, defaultValue) - override fun getString(key: String, defaultValue: String): String = - sharedPreferences.getString(key, defaultValue) ?: defaultValue - override fun getBoolean(resourceID: Int, defaultValue: Boolean): Boolean { return try { sharedPreferences.getBoolean(context.getString(resourceID), defaultValue) @@ -114,16 +124,16 @@ class SPImplementation @Inject constructor( } override fun getDouble(resourceID: Int, defaultValue: Double): Double = - SafeParse.stringToDouble(sharedPreferences.getString(context.getString(resourceID), defaultValue.toString())) + SafeParse.stringToDouble(sharedPreferences.getString(context.getString(resourceID), defaultValue.toString()), defaultValue) override fun getDouble(key: String, defaultValue: Double): Double = - SafeParse.stringToDouble(sharedPreferences.getString(key, defaultValue.toString())) + SafeParse.stringToDouble(sharedPreferences.getString(key, defaultValue.toString()), defaultValue) override fun getInt(resourceID: Int, defaultValue: Int): Int { return try { sharedPreferences.getInt(context.getString(resourceID), defaultValue) } catch (e: Exception) { - SafeParse.stringToInt(sharedPreferences.getString(context.getString(resourceID), defaultValue.toString())) + SafeParse.stringToInt(sharedPreferences.getString(context.getString(resourceID), defaultValue.toString()), defaultValue) } } @@ -131,7 +141,7 @@ class SPImplementation @Inject constructor( return try { sharedPreferences.getInt(key, defaultValue) } catch (e: Exception) { - SafeParse.stringToInt(sharedPreferences.getString(key, defaultValue.toString())) + SafeParse.stringToInt(sharedPreferences.getString(key, defaultValue.toString()), defaultValue) } } @@ -139,11 +149,7 @@ class SPImplementation @Inject constructor( return try { sharedPreferences.getLong(context.getString(resourceID), defaultValue) } catch (e: Exception) { - try { - SafeParse.stringToLong(sharedPreferences.getString(context.getString(resourceID), defaultValue.toString())) - } catch (e: Exception) { - defaultValue - } + SafeParse.stringToLong(sharedPreferences.getString(context.getString(resourceID), defaultValue.toString()), defaultValue) } } @@ -151,11 +157,7 @@ class SPImplementation @Inject constructor( return try { sharedPreferences.getLong(key, defaultValue) } catch (e: Exception) { - try { - SafeParse.stringToLong(sharedPreferences.getString(key, defaultValue.toString())) - } catch (e: Exception) { - defaultValue - } + SafeParse.stringToLong(sharedPreferences.getString(key, defaultValue.toString()), defaultValue) } } diff --git a/app-wear-shared/shared-impl/src/test/kotlin/info/nightscout/androidaps/TestBase.kt b/app-wear-shared/shared-impl/src/test/kotlin/info/nightscout/androidaps/TestBase.kt new file mode 100644 index 0000000000..4fd2aef548 --- /dev/null +++ b/app-wear-shared/shared-impl/src/test/kotlin/info/nightscout/androidaps/TestBase.kt @@ -0,0 +1,37 @@ +package info.nightscout.androidaps + +import info.nightscout.rx.AapsSchedulers +import info.nightscout.rx.TestAapsSchedulers +import info.nightscout.rx.logging.AAPSLoggerTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mockito +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.quality.Strictness +import java.util.Locale + +@ExtendWith(MockitoExtension::class) +@MockitoSettings(strictness = Strictness.LENIENT) +open class TestBase { + + val aapsLogger = AAPSLoggerTest() + val aapsSchedulers: AapsSchedulers = TestAapsSchedulers() + + @BeforeEach + fun setupLocale() { + Locale.setDefault(Locale.ENGLISH) + System.setProperty("disableFirebase", "true") + } + + // Workaround for Kotlin nullability. + // https://medium.com/@elye.project/befriending-kotlin-and-mockito-1c2e7b0ef791 + // https://stackoverflow.com/questions/30305217/is-it-possible-to-use-mockito-in-kotlin + fun anyObject(): T { + Mockito.any() + return uninitialized() + } + + @Suppress("Unchecked_Cast") + fun uninitialized(): T = null as T +} \ No newline at end of file diff --git a/app-wear-shared/shared-impl/src/test/kotlin/info/nightscout/androidaps/mocks/SharedPreferencesMock.kt b/app-wear-shared/shared-impl/src/test/kotlin/info/nightscout/androidaps/mocks/SharedPreferencesMock.kt new file mode 100644 index 0000000000..60c708e578 --- /dev/null +++ b/app-wear-shared/shared-impl/src/test/kotlin/info/nightscout/androidaps/mocks/SharedPreferencesMock.kt @@ -0,0 +1,123 @@ +package info.nightscout.androidaps.mocks + +import android.content.SharedPreferences +import android.content.SharedPreferences.OnSharedPreferenceChangeListener + +class SharedPreferencesMock : SharedPreferences { + + private val editor = EditorInternals() + + internal class EditorInternals : SharedPreferences.Editor { + + var innerMap: MutableMap = HashMap() + override fun putString(k: String, v: String?): SharedPreferences.Editor { + innerMap[k] = v + return this + } + + override fun putStringSet(k: String, set: Set?): SharedPreferences.Editor { + innerMap[k] = set + return this + } + + override fun putInt(k: String, i: Int): SharedPreferences.Editor { + innerMap[k] = i + return this + } + + override fun putLong(k: String, l: Long): SharedPreferences.Editor { + innerMap[k] = l + return this + } + + override fun putFloat(k: String, v: Float): SharedPreferences.Editor { + innerMap[k] = v + return this + } + + override fun putBoolean(k: String, b: Boolean): SharedPreferences.Editor { + innerMap[k] = b + return this + } + + override fun remove(k: String): SharedPreferences.Editor { + innerMap.remove(k) + return this + } + + override fun clear(): SharedPreferences.Editor { + innerMap.clear() + return this + } + + override fun commit(): Boolean { + return true + } + + override fun apply() {} + } + + override fun getAll(): Map { + return editor.innerMap + } + + override fun getString(k: String, s: String?): String? { + return if (editor.innerMap.containsKey(k)) { + editor.innerMap[k] as String? + } else { + s + } + } + + @Suppress("UNCHECKED_CAST") + override fun getStringSet(k: String, set: Set?): Set? { + return if (editor.innerMap.containsKey(k)) { + editor.innerMap[k] as Set? + } else { + set + } + } + + override fun getInt(k: String, i: Int): Int { + return if (editor.innerMap.containsKey(k)) { + editor.innerMap[k] as Int + } else { + i + } + } + + override fun getLong(k: String, l: Long): Long { + return if (editor.innerMap.containsKey(k)) { + editor.innerMap[k] as Long + } else { + l + } + } + + override fun getFloat(k: String, v: Float): Float { + return if (editor.innerMap.containsKey(k)) { + editor.innerMap[k] as Float + } else { + v + } + } + + override fun getBoolean(k: String, b: Boolean): Boolean { + return if (editor.innerMap.containsKey(k)) { + editor.innerMap[k] as Boolean + } else { + b + } + } + + override fun contains(k: String): Boolean { + return editor.innerMap.containsKey(k) + } + + override fun edit(): SharedPreferences.Editor { + return editor + } + + override fun registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener: OnSharedPreferenceChangeListener) {} + override fun unregisterOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener: OnSharedPreferenceChangeListener) {} +} \ No newline at end of file diff --git a/app-wear-shared/shared-impl/src/test/kotlin/info/nightscout/shared/impl/sharedPreferences/SPImplementationTest.kt b/app-wear-shared/shared-impl/src/test/kotlin/info/nightscout/shared/impl/sharedPreferences/SPImplementationTest.kt new file mode 100644 index 0000000000..b9e44c330c --- /dev/null +++ b/app-wear-shared/shared-impl/src/test/kotlin/info/nightscout/shared/impl/sharedPreferences/SPImplementationTest.kt @@ -0,0 +1,181 @@ +package info.nightscout.shared.impl.sharedPreferences + +import android.content.Context +import info.nightscout.androidaps.TestBase +import info.nightscout.androidaps.mocks.SharedPreferencesMock +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mock +import org.mockito.Mockito + +class SPImplementationTest : TestBase() { + + private val sharedPreferences: SharedPreferencesMock = SharedPreferencesMock() + @Mock lateinit var context: Context + + private lateinit var sut: SPImplementation + + private val someResource = 1 + private val someResource2 = 2 + + @BeforeEach + fun setUp() { + sut = SPImplementation(sharedPreferences, context) + Mockito.`when`(context.getString(someResource)).thenReturn("some_resource") + Mockito.`when`(context.getString(someResource2)).thenReturn("some_resource_2") + } + + @Test + fun edit() { + sut.edit { putBoolean("test", true) } + Assertions.assertTrue(sut.getBoolean("test", false)) + sut.edit { remove("test") } + Assertions.assertFalse(sut.contains("test")) + sut.edit { putBoolean(someResource, true) } + Assertions.assertTrue(sut.getBoolean(someResource, false)) + sut.edit { remove(someResource) } + Assertions.assertFalse(sut.contains(someResource)) + + sut.edit(commit = true) { putDouble("test", 1.0) } + Assertions.assertEquals(1.0, sut.getDouble("test", 2.0)) + sut.edit { putDouble(someResource, 1.0) } + Assertions.assertEquals(1.0, sut.getDouble(someResource, 2.0)) + sut.edit { clear() } + Assertions.assertFalse(sut.contains(someResource2)) + + sut.edit { putInt("test", 1) } + Assertions.assertEquals(1, sut.getInt("test", 2)) + sut.edit { putInt(someResource, 1) } + Assertions.assertEquals(1, sut.getInt(someResource, 2)) + sut.edit { clear() } + + sut.edit { putLong("test", 1L) } + Assertions.assertEquals(1L, sut.getLong("test", 2L)) + sut.edit { putLong(someResource, 1) } + Assertions.assertEquals(1L, sut.getLong(someResource, 2L)) + sut.edit { clear() } + + sut.edit { putString("test", "string") } + Assertions.assertEquals("string", sut.getString("test", "a")) + sut.edit { putString(someResource, "string") } + Assertions.assertEquals("string", sut.getString(someResource, "a")) + sut.edit { clear() } + } + + @Test + fun clear() { + sut.putBoolean("test", true) + Assertions.assertTrue(sut.getAll().containsKey("test")) + sut.clear() + Assertions.assertFalse(sut.getAll().containsKey("test")) + } + + @Test + fun contains() { + sut.putBoolean("test", true) + Assertions.assertTrue(sut.contains("test")) + sut.putBoolean(someResource, true) + Assertions.assertTrue(sut.contains(someResource)) + } + + @Test + fun remove() { + sut.putBoolean("test", true) + sut.remove("test") + Assertions.assertFalse(sut.contains("test")) + sut.putBoolean(someResource, true) + sut.remove(someResource) + Assertions.assertFalse(sut.contains(someResource)) + } + + @Test + fun getString() { + sut.putString("test", "string") + Assertions.assertTrue(sut.getString("test", "") == "string") + Assertions.assertTrue(sut.getString("test1", "") == "") + sut.putString(someResource, "string") + Assertions.assertTrue(sut.getString(someResource, "") == "string") + Assertions.assertTrue(sut.getString(someResource2, "") == "") + } + + @Test + fun getStringOrNull() { + sut.putString("test", "string") + Assertions.assertTrue(sut.getStringOrNull("test", "") == "string") + Assertions.assertNull(sut.getStringOrNull("test1", null)) + sut.putString(someResource, "string") + Assertions.assertTrue(sut.getStringOrNull(someResource, null) == "string") + Assertions.assertNull(sut.getStringOrNull(someResource2, null)) + } + + @Test + fun getBoolean() { + sut.putBoolean("test", true) + Assertions.assertTrue(sut.getBoolean("test", false)) + sut.putBoolean(someResource, true) + Assertions.assertTrue(sut.getBoolean(someResource, false)) + sut.putString("string_key", "a") + Assertions.assertTrue(sut.getBoolean("string_key", true)) + sut.putString(someResource, "a") + Assertions.assertTrue(sut.getBoolean(someResource, true)) + } + + @Test + fun getDouble() { + sut.putDouble("test", 1.0) + Assertions.assertEquals(1.0, sut.getDouble("test", 2.0)) + Assertions.assertEquals(2.0, sut.getDouble("test1", 2.0)) + sut.putDouble(someResource, 1.0) + Assertions.assertEquals(1.0, sut.getDouble(someResource, 2.0)) + Assertions.assertEquals(2.0, sut.getDouble(someResource2, 2.0)) + sut.putString("string_key", "a") + Assertions.assertEquals(1.0, sut.getDouble("string_key", 1.0)) + sut.putString(someResource, "a") + Assertions.assertEquals(1.0, sut.getDouble(someResource, 1.0)) + } + + @Test + fun getInt() { + sut.putInt("test", 1) + Assertions.assertEquals(1, sut.getInt("test", 2)) + Assertions.assertEquals(2, sut.getInt("test1", 2)) + sut.putInt(someResource, 1) + Assertions.assertEquals(1, sut.getInt(someResource, 2)) + Assertions.assertEquals(2, sut.getInt(someResource2, 2)) + sut.putString("string_key", "a") + Assertions.assertEquals(1, sut.getInt("string_key", 1)) + sut.putString(someResource, "a") + Assertions.assertEquals(1, sut.getInt(someResource, 1)) + } + + @Test + fun getLong() { + sut.putLong("test", 1L) + Assertions.assertEquals(1L, sut.getLong("test", 2L)) + Assertions.assertEquals(2L, sut.getLong("test1", 2L)) + sut.putLong(someResource, 1L) + Assertions.assertEquals(1L, sut.getLong(someResource, 2L)) + Assertions.assertEquals(2L, sut.getLong(someResource2, 2L)) + sut.putString("string_key", "a") + Assertions.assertEquals(1L, sut.getLong("string_key", 1L)) + sut.putString(someResource, "a") + Assertions.assertEquals(1L, sut.getLong(someResource, 1L)) + } + + @Test + fun incLong() { + sut.incLong(someResource) + Assertions.assertEquals(1L, sut.getLong(someResource, 3L)) + sut.incLong(someResource) + Assertions.assertEquals(2L, sut.getLong(someResource, 3L)) + } + + @Test + fun incInt() { + sut.incInt(someResource) + Assertions.assertEquals(1, sut.getInt(someResource, 3)) + sut.incInt(someResource) + Assertions.assertEquals(2, sut.getInt(someResource, 3)) + } +} \ No newline at end of file diff --git a/app-wear-shared/shared/src/main/java/info/nightscout/shared/SafeParse.kt b/app-wear-shared/shared/src/main/java/info/nightscout/shared/SafeParse.kt index f8d9aefa0b..c11631c338 100644 --- a/app-wear-shared/shared/src/main/java/info/nightscout/shared/SafeParse.kt +++ b/app-wear-shared/shared/src/main/java/info/nightscout/shared/SafeParse.kt @@ -2,7 +2,6 @@ package info.nightscout.shared object SafeParse { - // private static Logger log = StacktraceLoggerWrapper.getLogger(SafeParse.class); fun stringToDouble(inputString: String?, defaultValue: Double = 0.0): Double { var input = inputString ?: return defaultValue var result = defaultValue @@ -11,50 +10,50 @@ object SafeParse { if (input == "") return defaultValue try { result = input.toDouble() - } catch (e: Exception) { -// log.error("Error parsing " + input + " to double"); + } catch (ignored: Exception) { + // fail over to default } return result } - fun stringToFloat(inputString: String?): Float { - var input = inputString ?: return 0f - var result = 0f + fun stringToFloat(inputString: String?, defaultValue: Float = 0f): Float { + var input = inputString ?: return defaultValue + var result = defaultValue input = input.replace(",", ".") input = input.replace("−", "-") - if (input == "") return 0f + if (input == "") return defaultValue try { result = input.toFloat() - } catch (e: Exception) { -// log.error("Error parsing " + input + " to float"); + } catch (ignored: Exception) { + // fail over to default } return result } - fun stringToInt(inputString: String?): Int { - var input = inputString ?: return 0 - var result = 0 + fun stringToInt(inputString: String?, defaultValue: Int = 0): Int { + var input = inputString ?: return defaultValue + var result = defaultValue input = input.replace(",", ".") input = input.replace("−", "-") - if (input == "") return 0 + if (input == "") return defaultValue try { result = input.toInt() - } catch (e: Exception) { -// log.error("Error parsing " + input + " to int"); + } catch (ignored: Exception) { + // fail over to default } return result } - fun stringToLong(inputString: String?): Long { - var input = inputString ?: return 0L - var result = 0L + fun stringToLong(inputString: String?, defaultValue: Long = 0L): Long { + var input = inputString ?: return defaultValue + var result = defaultValue input = input.replace(",", ".") input = input.replace("−", "-") - if (input == "") return 0L + if (input == "") return defaultValue try { result = input.toLong() - } catch (e: Exception) { -// log.error("Error parsing " + input + " to long"); + } catch (ignored: Exception) { + // fail over to default } return result }