From 388af789948cc7409589e5853dea0b3f14ea239b Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Mon, 17 Feb 2020 23:38:10 -0800 Subject: Create new kpref model --- .../main/kotlin/ca/allanwang/kau/kpref/KPref.kt | 35 ++---- .../kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt | 132 ++++++++++++++++++--- .../kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt | 12 +- .../kotlin/ca/allanwang/kau/kpref/KPrefFactory.kt | 22 ++++ .../ca/allanwang/kau/kpref/KPrefSingleDelegate.kt | 14 ++- 5 files changed, 161 insertions(+), 54 deletions(-) create mode 100644 core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefFactory.kt (limited to 'core/src/main') diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt index fc7a76a..2f8a6aa 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt @@ -15,10 +15,7 @@ */ package ca.allanwang.kau.kpref -import android.content.Context -import android.content.SharedPreferences import ca.allanwang.kau.kotlin.ILazyResettable -import ca.allanwang.kau.logging.KL /** * Created by Allan Wang on 2017-06-07. @@ -32,30 +29,16 @@ import ca.allanwang.kau.logging.KL * Furthermore, all kprefs are held in the [prefMap], * so if you wish to reset a preference, you must also invalidate the kpref * from that map - * - * You may optionally override [deleteKeys]. This will be called on initialization - * And delete all keys returned from that method */ -open class KPref(builder: KPrefBuilder = KPrefBuilderAndroid) : KPrefBuilder by builder { - - lateinit var PREFERENCE_NAME: String - lateinit var sp: SharedPreferences +open class KPref private constructor( + val preferenceName: String, + val builder: KPrefBuilder +) : KPrefBuilder by builder { - fun initialize( - c: Context, - preferenceName: String, - sharedPrefs: SharedPreferences = c.applicationContext.getSharedPreferences(preferenceName, Context.MODE_PRIVATE) - ) { - PREFERENCE_NAME = preferenceName - sp = sharedPrefs - KL.d { "Shared Preference $preferenceName has been initialized" } - val toDelete = deleteKeys() - if (toDelete.isNotEmpty()) { - val edit = sp.edit() - toDelete.forEach { edit.remove(it) } - edit.apply() - } - } + constructor(preferenceName: String, factory: KPrefFactory) : this( + preferenceName, + factory.createBuilder(preferenceName) + ) internal val prefMap: MutableMap> = mutableMapOf() @@ -64,6 +47,4 @@ open class KPref(builder: KPrefBuilder = KPrefBuilderAndroid) : KPrefBuilder by } operator fun get(key: String): ILazyResettable<*>? = prefMap[key] - - open fun deleteKeys(): Array = arrayOf() } diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt index 8f6d0c5..b8fb8ea 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt @@ -15,22 +15,44 @@ */ package ca.allanwang.kau.kpref +import android.content.SharedPreferences + interface KPrefBuilder { - fun KPref.kpref(key: String, fallback: Boolean, postSetter: (value: Boolean) -> Unit = {}): KPrefDelegate + fun KPref.kpref( + key: String, + fallback: Boolean, + postSetter: (value: Boolean) -> Unit = {} + ): KPrefDelegate - fun KPref.kpref(key: String, fallback: Float, postSetter: (value: Float) -> Unit = {}): KPrefDelegate + fun KPref.kpref( + key: String, + fallback: Float, + postSetter: (value: Float) -> Unit = {} + ): KPrefDelegate @Deprecated( "Double is not supported in SharedPreferences; cast to float yourself", ReplaceWith("kpref(key, fallback.toFloat(), postSetter)"), DeprecationLevel.WARNING ) - fun KPref.kpref(key: String, fallback: Double, postSetter: (value: Float) -> Unit = {}): KPrefDelegate = + fun KPref.kpref( + key: String, + fallback: Double, + postSetter: (value: Float) -> Unit = {} + ): KPrefDelegate = kpref(key, fallback.toFloat(), postSetter) - fun KPref.kpref(key: String, fallback: Int, postSetter: (value: Int) -> Unit = {}): KPrefDelegate + fun KPref.kpref( + key: String, + fallback: Int, + postSetter: (value: Int) -> Unit = {} + ): KPrefDelegate - fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit = {}): KPrefDelegate + fun KPref.kpref( + key: String, + fallback: Long, + postSetter: (value: Long) -> Unit = {} + ): KPrefDelegate fun KPref.kpref( key: String, @@ -38,32 +60,97 @@ interface KPrefBuilder { postSetter: (value: Set) -> Unit = {} ): KPrefDelegate> - fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit = {}): KPrefDelegate + fun KPref.kpref( + key: String, + fallback: String, + postSetter: (value: String) -> Unit = {} + ): KPrefDelegate fun KPref.kprefSingle(key: String): KPrefSingleDelegate + + /** + * Remove keys from pref so they revert to the default + */ + fun KPref.deleteKeys(keys: Array) } -object KPrefBuilderAndroid : KPrefBuilder { +class KPrefBuilderAndroid(val sp: SharedPreferences) : KPrefBuilder { override fun KPref.kpref(key: String, fallback: Boolean, postSetter: (value: Boolean) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefBooleanTransaction, postSetter) + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefBooleanTransaction, + postSetter + ) override fun KPref.kpref(key: String, fallback: Float, postSetter: (value: Float) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefFloatTransaction, postSetter) + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefFloatTransaction, + postSetter + ) override fun KPref.kpref(key: String, fallback: Int, postSetter: (value: Int) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefIntTransaction, postSetter) + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefIntTransaction, + postSetter + ) override fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefLongTransaction, postSetter) - - override fun KPref.kpref(key: String, fallback: Set, postSetter: (value: Set) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefSetTransaction, postSetter) + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefLongTransaction, + postSetter + ) + + override fun KPref.kpref( + key: String, + fallback: Set, + postSetter: (value: Set) -> Unit + ) = + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefSetTransaction, + postSetter + ) override fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit) = - KPrefDelegateAndroid(key, fallback, this, KPrefStringTransaction, postSetter) - - override fun KPref.kprefSingle(key: String) = KPrefSingleDelegateAndroid(key, this) + KPrefDelegateAndroid( + key, + fallback, + this, + this@KPrefBuilderAndroid, + KPrefStringTransaction, + postSetter + ) + + override fun KPref.kprefSingle(key: String) = + KPrefSingleDelegateAndroid(key, this, this@KPrefBuilderAndroid) + + override fun KPref.deleteKeys(keys: Array) { + // Remove pref listing + sp.edit().apply { + keys.forEach { remove(it) } + }.apply() + // Clear cached values + keys.forEach { prefMap[it]?.invalidate() } + } } object KPrefBuilderInMemory : KPrefBuilder { @@ -80,11 +167,20 @@ object KPrefBuilderInMemory : KPrefBuilder { override fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit) = KPrefDelegateInMemory(key, fallback, this, postSetter) - override fun KPref.kpref(key: String, fallback: Set, postSetter: (value: Set) -> Unit) = + override fun KPref.kpref( + key: String, + fallback: Set, + postSetter: (value: Set) -> Unit + ) = KPrefDelegateInMemory(key, fallback, this, postSetter) override fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit) = KPrefDelegateInMemory(key, fallback, this, postSetter) override fun KPref.kprefSingle(key: String) = KPrefSingleDelegateInMemory(key, this) + + override fun KPref.deleteKeys(keys: Array) { + // Clear cached values + keys.forEach { prefMap[it]?.invalidate() } + } } diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt index 684b139..d54c54d 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt @@ -15,6 +15,7 @@ */ package ca.allanwang.kau.kpref +import android.content.SharedPreferences import ca.allanwang.kau.kotlin.ILazyResettable /** @@ -35,19 +36,22 @@ class KPrefDelegateAndroid internal constructor( private val key: String, private val fallback: T, private val pref: KPref, + private val prefBuilder: KPrefBuilderAndroid, private val transaction: KPrefTransaction, private var postSetter: (value: T) -> Unit = {} ) : KPrefDelegate { private object UNINITIALIZED + private val sp: SharedPreferences get() = prefBuilder.sp + @Volatile private var _value: Any? = UNINITIALIZED private val lock = this init { if (pref.prefMap.containsKey(key)) - throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") + throw KPrefException("$key is already used elsewhere in preference ${pref.preferenceName}") pref.prefMap[key] = this@KPrefDelegateAndroid } @@ -67,7 +71,7 @@ class KPrefDelegateAndroid internal constructor( if (_v2 !== UNINITIALIZED) { _v2 as T } else { - _value = transaction.get(pref.sp, key, fallback) + _value = transaction.get(sp, key, fallback) _value as T } } @@ -79,7 +83,7 @@ class KPrefDelegateAndroid internal constructor( override operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) { _value = t - val editor = pref.sp.edit() + val editor = sp.edit() transaction.set(editor, key, t) editor.apply() postSetter(t) @@ -101,7 +105,7 @@ class KPrefDelegateInMemory internal constructor( init { if (pref.prefMap.containsKey(key)) - throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") + throw KPrefException("$key is already used elsewhere in preference ${pref.preferenceName}") pref.prefMap[key] = this } diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefFactory.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefFactory.kt new file mode 100644 index 0000000..0c49b88 --- /dev/null +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefFactory.kt @@ -0,0 +1,22 @@ +package ca.allanwang.kau.kpref + +import android.content.Context + +interface KPrefFactory { + fun createBuilder(preferenceName: String): KPrefBuilder +} + +/** + * Default factory for Android preferences + */ +class KPrefFactoryAndroid(context: Context) : KPrefFactory { + + val context: Context = context.applicationContext + + override fun createBuilder(preferenceName: String): KPrefBuilder = + KPrefBuilderAndroid(context.getSharedPreferences(preferenceName, Context.MODE_PRIVATE)) +} + +object KPrefFactoryInMemory : KPrefFactory { + override fun createBuilder(preferenceName: String): KPrefBuilder = KPrefBuilderInMemory +} \ No newline at end of file diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt index ae1f855..9d03a16 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt @@ -15,6 +15,7 @@ */ package ca.allanwang.kau.kpref +import android.content.SharedPreferences import ca.allanwang.kau.kotlin.ILazyResettable /** @@ -29,16 +30,19 @@ interface KPrefSingleDelegate : ILazyResettable class KPrefSingleDelegateAndroid internal constructor( private val key: String, - private val pref: KPref + private val pref: KPref, + private val prefBuilder: KPrefBuilderAndroid ) : KPrefSingleDelegate { @Volatile private var _value: Boolean? = null private val lock = this + private val sp: SharedPreferences get() = prefBuilder.sp + init { if (pref.prefMap.containsKey(key)) - throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") + throw KPrefException("$key is already used elsewhere in preference ${pref.preferenceName}") pref.prefMap[key] = this } @@ -57,9 +61,9 @@ class KPrefSingleDelegateAndroid internal constructor( if (_v2 != null) { _v2 } else { - _value = pref.sp.getBoolean(key, true) + _value = sp.getBoolean(key, true) if (_value!!) { - pref.sp.edit().putBoolean(key, false).apply() + sp.edit().putBoolean(key, false).apply() _value = false true } else false @@ -82,7 +86,7 @@ class KPrefSingleDelegateInMemory internal constructor( init { if (pref.prefMap.containsKey(key)) - throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") + throw KPrefException("$key is already used elsewhere in preference ${pref.preferenceName}") pref.prefMap[key] = this } -- cgit v1.2.3 From d67d4a1204796377040a1769175d5798ce09408b Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 23 Feb 2020 13:02:25 -0800 Subject: Fix kpref tests --- .../androidTest/kotlin/ca/allanwang/kau/Utils.kt | 7 ++++ .../kotlin/ca/allanwang/kau/kpref/KPrefTest.kt | 38 +++++++++-------- .../main/kotlin/ca/allanwang/kau/kpref/KPref.kt | 6 +++ .../kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt | 21 +++++----- sample/build.gradle | 2 +- .../ca/allanwang/kau/sample/KPrefViewTest.kt | 41 ++++++++---------- .../ca/allanwang/kau/sample/SampleTestApp.kt | 49 +++++++++++++++++++++- .../ca/allanwang/kau/sample/utils/EspressoUtils.kt | 2 + 8 files changed, 113 insertions(+), 53 deletions(-) create mode 100644 core/src/androidTest/kotlin/ca/allanwang/kau/Utils.kt (limited to 'core/src/main') diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/Utils.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/Utils.kt new file mode 100644 index 0000000..33252d6 --- /dev/null +++ b/core/src/androidTest/kotlin/ca/allanwang/kau/Utils.kt @@ -0,0 +1,7 @@ +package ca.allanwang.kau + +import android.content.Context +import androidx.test.platform.app.InstrumentationRegistry + +val context: Context + get() = InstrumentationRegistry.getInstrumentation().context \ No newline at end of file diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt index 04c6444..222f0f5 100644 --- a/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt +++ b/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt @@ -16,14 +16,14 @@ package ca.allanwang.kau.kpref import android.annotation.SuppressLint -import android.content.Context -import androidx.test.core.app.ApplicationProvider +import android.content.SharedPreferences import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest -import kotlin.test.assertEquals +import ca.allanwang.kau.context import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import kotlin.test.assertEquals /** * Created by Allan Wang on 2017-08-01. @@ -33,13 +33,11 @@ import org.junit.runner.RunWith class KPrefTest { lateinit var androidPref: TestPref + lateinit var androidSp: SharedPreferences lateinit var memPref: TestPref - class TestPref(builder: KPrefBuilder) : KPref(builder) { - - init { - initialize(ApplicationProvider.getApplicationContext(), "kpref_test_${System.currentTimeMillis()}") - } + class TestPref(factory: KPrefFactory) : + KPref("kpref_test_${System.currentTimeMillis()}", factory) { var postSetterCount: Int = 0 @@ -60,9 +58,10 @@ class KPrefTest { @Before fun init() { - androidPref = TestPref(KPrefBuilderAndroid) - androidPref.sp.edit().clear().commit() - memPref = TestPref(KPrefBuilderInMemory) + androidPref = TestPref(KPrefFactoryAndroid(context)) + androidSp = (androidPref.builder as KPrefBuilderAndroid).sp + androidSp.edit().clear().commit() + memPref = TestPref(KPrefFactoryInMemory) } private fun pref(action: TestPref.() -> Unit) { @@ -70,7 +69,11 @@ class KPrefTest { memPref.action() } - private fun assertPrefEquals(expected: T, actual: TestPref.() -> T, message: String? = null) { + private fun assertPrefEquals( + expected: T, + actual: TestPref.() -> T, + message: String? = null + ) { assertEquals(expected, androidPref.actual(), "Android KPrefs: $message") assertEquals(expected, memPref.actual(), "In Mem KPrefs: $message") } @@ -83,7 +86,7 @@ class KPrefTest { assertPrefEquals("hello", { hello }) assertPrefEquals(3, { set.size }) assertPrefEquals(setOf("po", "ta", "to"), { set }) - assertEquals(0, androidPref.sp.all.size, "Defaults should not be set automatically") + assertEquals(0, androidSp.all.size, "Defaults should not be set automatically") } @Test @@ -93,8 +96,8 @@ class KPrefTest { assertPrefEquals(2, { one }) pref { hello = "goodbye" } assertPrefEquals("goodbye", { hello }) - assertEquals(androidPref.hello, androidPref.sp.getString("hello", "badfallback")) - assertEquals(2, androidPref.sp.all.size) + assertEquals(androidPref.hello, androidSp.getString("hello", "badfallback")) + assertEquals(2, androidSp.all.size) } @SuppressLint("CommitPrefEdits") @@ -104,9 +107,10 @@ class KPrefTest { assertPrefEquals(2, { one }) assertPrefEquals(6, { prefMap.size }, "Prefmap does not have all elements") pref { reset() } // only invalidates our lazy delegate; doesn't change the actual pref - assertPrefEquals(2, { one }, "Kpref did not properly fetch from shared prefs") + assertEquals(1, memPref.one, "Memory Kpref did not invalidate value") + assertEquals(2, androidPref.one, "Android Kpref did not properly fetch from shared prefs") // Android pref only - androidPref.sp.edit().putInt("one", -1).commit() + androidSp.edit().putInt("one", -1).commit() assertEquals(2, androidPref.one, "Lazy kpref should still retain old value") androidPref.reset() assertEquals(-1, androidPref.one, "Kpref did not refetch from shared prefs upon reset") diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt index 2f8a6aa..a45d66d 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt @@ -42,6 +42,12 @@ open class KPref private constructor( internal val prefMap: MutableMap> = mutableMapOf() + fun add(entry : KPrefDelegate<*>) { + if (prefMap.containsKey(entry.key)) + throw KPrefException("${entry.key} is already used elsewhere in preference $preferenceName") + prefMap[entry.key] = entry + } + fun reset() { prefMap.values.forEach { it.invalidate() } } diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt index d54c54d..c17d3df 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt @@ -27,13 +27,14 @@ import ca.allanwang.kau.kotlin.ILazyResettable */ interface KPrefDelegate : ILazyResettable { + val key: String operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) } class KPrefException(message: String) : IllegalAccessException(message) class KPrefDelegateAndroid internal constructor( - private val key: String, + override val key: String, private val fallback: T, private val pref: KPref, private val prefBuilder: KPrefBuilderAndroid, @@ -50,9 +51,7 @@ class KPrefDelegateAndroid internal constructor( private val lock = this init { - if (pref.prefMap.containsKey(key)) - throw KPrefException("$key is already used elsewhere in preference ${pref.preferenceName}") - pref.prefMap[key] = this@KPrefDelegateAndroid + pref.add(this) } override fun invalidate() { @@ -79,7 +78,8 @@ class KPrefDelegateAndroid internal constructor( override fun isInitialized(): Boolean = _value !== UNINITIALIZED - override fun toString(): String = if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." + override fun toString(): String = + if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." override operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) { _value = t @@ -91,7 +91,7 @@ class KPrefDelegateAndroid internal constructor( } class KPrefDelegateInMemory internal constructor( - private val key: String, + override val key: String, private val fallback: T, private val pref: KPref, private var postSetter: (value: T) -> Unit = {} @@ -104,13 +104,11 @@ class KPrefDelegateInMemory internal constructor( private val lock = this init { - if (pref.prefMap.containsKey(key)) - throw KPrefException("$key is already used elsewhere in preference ${pref.preferenceName}") - pref.prefMap[key] = this + pref.add(this) } override fun invalidate() { - // No op + _value = UNINITIALIZED } @Suppress("UNCHECKED_CAST") @@ -133,7 +131,8 @@ class KPrefDelegateInMemory internal constructor( override fun isInitialized(): Boolean = _value !== UNINITIALIZED - override fun toString(): String = if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." + override fun toString(): String = + if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." override operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) { _value = t diff --git a/sample/build.gradle b/sample/build.gradle index 2bd5ba8..77165e8 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -26,7 +26,7 @@ android { versionName androidGitVersion.name() versionCode androidGitVersion.code() multiDexEnabled true - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "ca.allanwang.kau.sample.SampleTestRunner" } viewBinding { enabled = true diff --git a/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/KPrefViewTest.kt b/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/KPrefViewTest.kt index 5847a94..156b66f 100644 --- a/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/KPrefViewTest.kt +++ b/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/KPrefViewTest.kt @@ -26,7 +26,6 @@ import androidx.test.espresso.matcher.ViewMatchers.withChild import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest -import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.ActivityTestRule import org.hamcrest.BaseMatcher import org.hamcrest.Description @@ -35,13 +34,11 @@ import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.instanceOf import org.junit.Rule import org.junit.Test +import org.junit.rules.RuleChain +import org.junit.rules.TestRule import org.junit.runner.RunWith -import org.koin.android.ext.koin.androidContext -import org.koin.core.context.startKoin -import org.koin.core.context.stopKoin import org.koin.test.KoinTest import org.koin.test.inject -import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -55,24 +52,18 @@ import kotlin.test.assertTrue @MediumTest class KPrefViewTest : KoinTest { - @get:Rule val activity: ActivityTestRule = ActivityTestRule(MainActivity::class.java) + @get:Rule + val rule: TestRule = RuleChain.outerRule(SampleTestRule()).around(activity) + + private val pref: KPrefSample by inject() + @BeforeTest fun before() { - startKoin { - androidContext(InstrumentationRegistry.getInstrumentation().context) - modules(listOf(SampleApp.prefModule(), SampleTestApp.prefFactoryModule())) - } - } - - @AfterTest - fun after() { - stopKoin() + pref.reset() } - private val pref: KPrefSample by inject() - fun verifyCheck(checked: Boolean): Matcher { return object : BoundedMatcher(View::class.java) { @@ -132,20 +123,24 @@ class KPrefViewTest : KoinTest { fun dependentCheckboxToggle() { val checkbox2 = onCheckboxView(withChild(withText(R.string.checkbox_2))) val checkbox3 = - onCheckboxView(withChild(withText(R.string.checkbox_3)), withChild(withText(R.string.desc_dependent))) + onCheckboxView( + withChild(withText(R.string.checkbox_3)), + withChild(withText(R.string.desc_dependent)) + ) assertFalse(pref.check2, "check2 not normalized") assertFalse(pref.check3, "check3 not normalized") - checkbox3.verifyCheck("checkbox3 init", true, true) + checkbox2.verifyCheck("checkbox2 init", checked = false, enabled = true) + checkbox3.verifyCheck("checkbox3 init", checked = false, enabled = false) checkbox3.perform(click()) - checkbox3.verifyCheck("checkbox3 after click", false, true) + checkbox3.verifyCheck("checkbox3 after disabled click", checked = false, enabled = false) checkbox2.perform(click()) - checkbox2.verifyCheck("checkbox2 after click", false, true) - checkbox3.verifyCheck("checkbox3 after checkbox2 click", false, false) + checkbox2.verifyCheck("checkbox2 after click", checked = true, enabled = true) + checkbox3.verifyCheck("checkbox3 after checkbox2 click", checked = false, enabled = true) checkbox3.perform(click()) - checkbox3.verifyCheck("checkbox3 after disabled click", false, false) + checkbox3.verifyCheck("checkbox3 after enabled click", checked = true, enabled = true) } } diff --git a/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/SampleTestApp.kt b/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/SampleTestApp.kt index 4b0c4a7..8705fbc 100644 --- a/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/SampleTestApp.kt +++ b/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/SampleTestApp.kt @@ -1,10 +1,57 @@ package ca.allanwang.kau.sample +import android.app.Application +import android.content.Context +import androidx.test.runner.AndroidJUnitRunner import ca.allanwang.kau.kpref.KPrefFactory import ca.allanwang.kau.kpref.KPrefFactoryInMemory +import ca.allanwang.kau.logging.KL +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement +import org.koin.android.ext.koin.androidContext +import org.koin.android.ext.koin.androidLogger +import org.koin.core.KoinComponent +import org.koin.core.context.startKoin +import org.koin.core.get import org.koin.dsl.module -object SampleTestApp { +class SampleTestRunner : AndroidJUnitRunner() { + override fun newApplication( + cl: ClassLoader?, + className: String?, + context: Context? + ): Application { + return super.newApplication(cl, SampleTestApp::class.java.name, context) + } +} + +class SampleTestRule : TestRule { + override fun apply(base: Statement, description: Description): Statement = + object : Statement(), KoinComponent { + override fun evaluate() { + + // Reset prefs + val pref: KPrefSample = get() + pref.reset() + + base.evaluate() + } + } +} + +class SampleTestApp : Application() { + override fun onCreate() { + super.onCreate() + startKoin { + if (BuildConfig.DEBUG) { + androidLogger() + } + androidContext(this@SampleTestApp) + modules(listOf(prefFactoryModule(), SampleApp.prefModule())) + } + } + fun prefFactoryModule() = module { single { KPrefFactoryInMemory diff --git a/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/utils/EspressoUtils.kt b/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/utils/EspressoUtils.kt index 09ad00a..2a6f0a9 100644 --- a/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/utils/EspressoUtils.kt +++ b/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/utils/EspressoUtils.kt @@ -15,6 +15,8 @@ */ package ca.allanwang.kau.sample.utils +import android.content.Context +import androidx.test.platform.app.InstrumentationRegistry import org.hamcrest.BaseMatcher import org.hamcrest.Description import org.hamcrest.Matcher -- cgit v1.2.3 From 0e7e43f7f778a206b0b30c6997c7c36494e6c142 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 23 Feb 2020 13:40:29 -0800 Subject: Add delete keys function --- core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt | 10 +++++++++- core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt | 6 +++--- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'core/src/main') diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt index a45d66d..7f75370 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt @@ -42,7 +42,7 @@ open class KPref private constructor( internal val prefMap: MutableMap> = mutableMapOf() - fun add(entry : KPrefDelegate<*>) { + fun add(entry: KPrefDelegate<*>) { if (prefMap.containsKey(entry.key)) throw KPrefException("${entry.key} is already used elsewhere in preference $preferenceName") prefMap[entry.key] = entry @@ -53,4 +53,12 @@ open class KPref private constructor( } operator fun get(key: String): ILazyResettable<*>? = prefMap[key] + + /** + * Exposed key deletion function from builder. + * To avoid recursion, this type uses vararg + */ + fun deleteKeys(vararg keys: String) { + deleteKeys(keys) + } } diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt index b8fb8ea..7a35ac2 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt @@ -71,7 +71,7 @@ interface KPrefBuilder { /** * Remove keys from pref so they revert to the default */ - fun KPref.deleteKeys(keys: Array) + fun KPref.deleteKeys(keys: Array) } class KPrefBuilderAndroid(val sp: SharedPreferences) : KPrefBuilder { @@ -143,7 +143,7 @@ class KPrefBuilderAndroid(val sp: SharedPreferences) : KPrefBuilder { override fun KPref.kprefSingle(key: String) = KPrefSingleDelegateAndroid(key, this, this@KPrefBuilderAndroid) - override fun KPref.deleteKeys(keys: Array) { + override fun KPref.deleteKeys(keys: Array) { // Remove pref listing sp.edit().apply { keys.forEach { remove(it) } @@ -179,7 +179,7 @@ object KPrefBuilderInMemory : KPrefBuilder { override fun KPref.kprefSingle(key: String) = KPrefSingleDelegateInMemory(key, this) - override fun KPref.deleteKeys(keys: Array) { + override fun KPref.deleteKeys(keys: Array) { // Clear cached values keys.forEach { prefMap[it]?.invalidate() } } -- cgit v1.2.3