From a27c25406f43f808750d4357384db549f7af7cb6 Mon Sep 17 00:00:00 2001 From: Lachlan McKee Date: Tue, 7 Feb 2023 13:15:57 +0000 Subject: [PATCH] Added tests for binder lifecycle extensions --- detekt.yml | 12 + .../lifecycle/LifecycleExtensionsTest.kt | 243 ++++++++++++++++++ .../android/lifecycle/TestLifecycleOwner.kt | 17 ++ 3 files changed, 272 insertions(+) create mode 100644 mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/LifecycleExtensionsTest.kt create mode 100644 mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/TestLifecycleOwner.kt diff --git a/detekt.yml b/detekt.yml index 0c5f52ac..bb509cda 100644 --- a/detekt.yml +++ b/detekt.yml @@ -1,2 +1,14 @@ config: warningsAsErrors: true + +style: + ForbiddenComment: + allowedPatterns: 'https://github.com/badoo/MVICore/issues/*' + MagicNumber: + excludes: [ '**/test/**', '**/*Test.kt' ] + MaxLineLength: + excludes: [ '**/test/**', '**/*.Test.kt', '**/*.Spec.kt' ] + excludeCommentStatements: true + WildcardImport: + active: true + excludeImports: [ ] diff --git a/mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/LifecycleExtensionsTest.kt b/mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/LifecycleExtensionsTest.kt new file mode 100644 index 00000000..805ee164 --- /dev/null +++ b/mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/LifecycleExtensionsTest.kt @@ -0,0 +1,243 @@ +package com.badoo.mvicore.android.lifecycle + +import androidx.arch.core.executor.ArchTaskExecutor +import androidx.arch.core.executor.TaskExecutor +import androidx.lifecycle.Lifecycle +import io.reactivex.functions.Consumer +import io.reactivex.subjects.PublishSubject +import org.junit.After +import org.junit.Before +import org.junit.Test +import kotlin.test.assertEquals + +class LifecycleExtensionsTest { + private val subject = PublishSubject.create() + private val consumerTester = ConsumerTester() + private val testLifecycleOwner = TestLifecycleOwner() + + @Before + fun setup() { + ArchTaskExecutor.getInstance() + .setDelegate(object : TaskExecutor() { + override fun executeOnDiskIO(runnable: Runnable) = runnable.run() + override fun postToMainThread(runnable: Runnable) = runnable.run() + override fun isMainThread(): Boolean = true + }) + } + + @After + fun teardown() { + ArchTaskExecutor.getInstance().setDelegate(null) + } + + @Test + fun `GIVEN initial lifecycle not set AND createDestroy WHEN event emitted THEN consumer not invoked`() { + testLifecycleOwner.lifecycle.createDestroy { + bind(subject to consumerTester) + } + + subject.onNext(Unit) + + consumerTester.verifyNotInvoked() + assertEquals(false, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is created AND createDestroy WHEN event emitted THEN consumer invoked AND observers exist`() { + testLifecycleOwner.lifecycle.createDestroy { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.CREATED + + subject.onNext(Unit) + + consumerTester.verifyInvoked() + assertEquals(true, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is started AND createDestroy WHEN event emitted THEN consumer invoked AND observers exist`() { + testLifecycleOwner.lifecycle.createDestroy { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.STARTED + + subject.onNext(Unit) + + consumerTester.verifyInvoked() + assertEquals(true, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is resumed AND createDestroy WHEN event emitted THEN consumer invoked AND observers exist`() { + testLifecycleOwner.lifecycle.createDestroy { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.RESUMED + + subject.onNext(Unit) + + consumerTester.verifyInvoked() + assertEquals(true, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is created AND createDestroy AND lifecycle moved to destroyed WHEN event emitted THEN consumer not invoked AND no observers`() { + testLifecycleOwner.lifecycle.createDestroy { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.CREATED + testLifecycleOwner.state = Lifecycle.State.DESTROYED + + subject.onNext(Unit) + + consumerTester.verifyNotInvoked() + assertEquals(false, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle not set AND startStop WHEN event emitted THEN consumer not invoked AND no observers`() { + testLifecycleOwner.lifecycle.startStop { + bind(subject to consumerTester) + } + + subject.onNext(Unit) + + consumerTester.verifyNotInvoked() + assertEquals(false, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is created AND startStop WHEN event emitted THEN consumer not invoked AND no observers`() { + testLifecycleOwner.lifecycle.startStop { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.CREATED + + subject.onNext(Unit) + + consumerTester.verifyNotInvoked() + assertEquals(false, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is started AND startStop WHEN event emitted THEN consumer invoked AND observers exist`() { + testLifecycleOwner.lifecycle.startStop { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.STARTED + + subject.onNext(Unit) + + consumerTester.verifyInvoked() + assertEquals(true, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is resumed AND startStop WHEN event emitted THEN consumer invoked AND observers exist`() { + testLifecycleOwner.lifecycle.startStop { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.RESUMED + + subject.onNext(Unit) + + consumerTester.verifyInvoked() + assertEquals(true, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is created AND startStop AND lifecycle moved to destroyed WHEN event emitted THEN consumer not invoked AND no observers`() { + testLifecycleOwner.lifecycle.startStop { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.CREATED + testLifecycleOwner.state = Lifecycle.State.DESTROYED + + subject.onNext(Unit) + + consumerTester.verifyNotInvoked() + assertEquals(false, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle not set AND resumePause WHEN event emitted THEN consumer not invoked AND no observers`() { + testLifecycleOwner.lifecycle.resumePause { + bind(subject to consumerTester) + } + + subject.onNext(Unit) + + consumerTester.verifyNotInvoked() + assertEquals(false, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is created AND resumePause WHEN event emitted THEN consumer not invoked AND no observers`() { + testLifecycleOwner.lifecycle.resumePause { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.CREATED + + subject.onNext(Unit) + + consumerTester.verifyNotInvoked() + assertEquals(false, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is started AND resumePause WHEN event emitted THEN consumer not invoked AND no observers`() { + testLifecycleOwner.lifecycle.resumePause { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.STARTED + + subject.onNext(Unit) + + consumerTester.verifyNotInvoked() + assertEquals(false, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is resumed AND resumePause WHEN event emitted THEN consumer invoked AND observers exist`() { + testLifecycleOwner.lifecycle.resumePause { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.RESUMED + + subject.onNext(Unit) + + consumerTester.verifyInvoked() + assertEquals(true, subject.hasObservers()) + } + + @Test + fun `GIVEN initial lifecycle is created AND resumePause AND lifecycle moved to destroyed WHEN event emitted THEN consumer not invoked AND no observers`() { + testLifecycleOwner.lifecycle.resumePause { + bind(subject to consumerTester) + } + testLifecycleOwner.state = Lifecycle.State.CREATED + testLifecycleOwner.state = Lifecycle.State.DESTROYED + + subject.onNext(Unit) + + consumerTester.verifyNotInvoked() + assertEquals(false, subject.hasObservers()) + } + + private class ConsumerTester : Consumer { + private var wasCalled: Boolean = false + + override fun accept(t: Unit?) { + wasCalled = true + } + + fun verifyInvoked() { + assertEquals(true, wasCalled) + } + + fun verifyNotInvoked() { + assertEquals(false, wasCalled) + } + } +} diff --git a/mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/TestLifecycleOwner.kt b/mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/TestLifecycleOwner.kt new file mode 100644 index 00000000..dea96915 --- /dev/null +++ b/mvicore-android/src/test/java/com/badoo/mvicore/android/lifecycle/TestLifecycleOwner.kt @@ -0,0 +1,17 @@ +package com.badoo.mvicore.android.lifecycle + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry + +class TestLifecycleOwner : LifecycleOwner { + private val registry = LifecycleRegistry(this) + + var state: Lifecycle.State + get() = registry.currentState + set(value) { + registry.currentState = value + } + + override fun getLifecycle(): Lifecycle = registry +}