diff options
8 files changed, 113 insertions, 53 deletions
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<Context>(), "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 <T> assertPrefEquals(expected: T, actual: TestPref.() -> T, message: String? = null) { + private fun <T> 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<String, ILazyResettable<*>> = 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<T> : ILazyResettable<T> { + val key: String operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) } class KPrefException(message: String) : IllegalAccessException(message) class KPrefDelegateAndroid<T> 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<T> 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<T> 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<T> internal constructor( } class KPrefDelegateInMemory<T> 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<T> 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<T> 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<MainActivity> = 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<View> { return object : BoundedMatcher<View, View>(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<KPrefFactory> { 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 |