diff --git a/src/main/kotlin/com/mvcoding/mvp/DataSource.kt b/src/main/kotlin/com/mvcoding/mvp/DataSource.kt index a920bf9..bde9556 100644 --- a/src/main/kotlin/com/mvcoding/mvp/DataSource.kt +++ b/src/main/kotlin/com/mvcoding/mvp/DataSource.kt @@ -2,4 +2,6 @@ package com.mvcoding.mvp interface DataSource { fun data(): O -} \ No newline at end of file +} + +fun DataSource.function(): () -> O = { data() } \ No newline at end of file diff --git a/src/main/kotlin/com/mvcoding/mvp/DataWriter.kt b/src/main/kotlin/com/mvcoding/mvp/DataWriter.kt new file mode 100644 index 0000000..47d5f16 --- /dev/null +++ b/src/main/kotlin/com/mvcoding/mvp/DataWriter.kt @@ -0,0 +1,7 @@ +package com.mvcoding.mvp + +interface DataWriter { + fun write(data: DATA) +} + +fun DataWriter.function(): (DATA) -> Unit = { write(it) } \ No newline at end of file diff --git a/src/main/kotlin/com/mvcoding/mvp/behaviors/SingleSelectItemBehavior.kt b/src/main/kotlin/com/mvcoding/mvp/behaviors/SingleSelectItemBehavior.kt index c5dfb1c..dd88366 100644 --- a/src/main/kotlin/com/mvcoding/mvp/behaviors/SingleSelectItemBehavior.kt +++ b/src/main/kotlin/com/mvcoding/mvp/behaviors/SingleSelectItemBehavior.kt @@ -1,9 +1,6 @@ package com.mvcoding.mvp.behaviors -import com.mvcoding.mvp.Behavior -import com.mvcoding.mvp.O -import com.mvcoding.mvp.Presenter -import com.mvcoding.mvp.RxSchedulers +import com.mvcoding.mvp.* import com.mvcoding.mvp.behaviors.SingleSelectItemBehavior.SingleSelectState.* import io.reactivex.rxkotlin.withLatestFrom @@ -14,6 +11,14 @@ class SingleSelectItemBehavior Unit, private val schedulers: RxSchedulers) : Behavior() { + constructor( + item: ITEM, + noItem: ITEM, + selectedItemSource: DataSource, + selectedItemWriter: DataWriter, + schedulers: RxSchedulers) : + this(item, noItem, selectedItemSource.function(), selectedItemWriter.function(), schedulers) + override fun onViewAttached(view: VIEW) { super.onViewAttached(view) diff --git a/src/main/kotlin/com/mvcoding/mvp/data/FunctionDataWriter.kt b/src/main/kotlin/com/mvcoding/mvp/data/FunctionDataWriter.kt new file mode 100644 index 0000000..19845d6 --- /dev/null +++ b/src/main/kotlin/com/mvcoding/mvp/data/FunctionDataWriter.kt @@ -0,0 +1,9 @@ +package com.mvcoding.mvp.data + +import com.mvcoding.mvp.DataWriter + +class FunctionDataWriter(private val dataWriter: (DATA) -> Unit) : DataWriter { + override fun write(data: DATA) = dataWriter(data) +} + +fun ((DATA) -> Unit).dataWriter() = FunctionDataWriter(this) \ No newline at end of file diff --git a/src/test/kotlin/com/mvcoding/mvp/behaviors/SingleSelectItemBehaviorTest.kt b/src/test/kotlin/com/mvcoding/mvp/behaviors/SingleSelectItemBehaviorTest.kt index a152f46..8aeec1e 100644 --- a/src/test/kotlin/com/mvcoding/mvp/behaviors/SingleSelectItemBehaviorTest.kt +++ b/src/test/kotlin/com/mvcoding/mvp/behaviors/SingleSelectItemBehaviorTest.kt @@ -2,120 +2,230 @@ package com.mvcoding.mvp.behaviors import com.jakewharton.rxrelay2.PublishRelay import com.mvcoding.mvp.O +import com.mvcoding.mvp.Presenter import com.mvcoding.mvp.trampolines -import com.nhaarman.mockitokotlin2.* -import org.junit.Before +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.never +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import io.reactivex.Observable import org.junit.Test class SingleSelectItemBehaviorTest { - private val selectsRelay = PublishRelay.create() - private val item = "item" private val otherItem = "otherItem" private val noItem = "" - private val getSelectedItem = mock<() -> O>() - private val setSelectedItem = mock<(String) -> Unit>() - private val view = mock>() - private val behavior = SingleSelectItemBehavior( - item, - noItem, - getSelectedItem, - setSelectedItem, - trampolines) - - @Before - fun setUp() { - whenever(view.selects()).thenReturn(selectsRelay) - } - @Test fun `sets item selected after select when nothing was selected yet`() { - whenever(getSelectedItem()).thenReturn(O.just(noItem)) - behavior attach view - - select() - - verify(setSelectedItem).invoke(item) + testSetsItemSelectedAfterSelectWhenNothingWasSelectedYet(item, noItem, createPresenter()) } @Test - fun `sets item selected after select when other item is selected`() { - whenever(getSelectedItem()).thenReturn(O.just(otherItem)) - behavior attach view - - select() - - verify(setSelectedItem).invoke(item) + fun `sets item selected after select when other item was selected`() { + testSetsItemSelectedAfterSelectWhenOtherItemWasSelected(item, otherItem, createPresenter()) } @Test fun `sets item not selected after select when this item was selected`() { - whenever(getSelectedItem()).thenReturn(O.just(item)) - behavior attach view - - select() - - verify(setSelectedItem).invoke(noItem) + testSetsItemNotSelectedAfterSelectWhenThisItemWasSelected(item, noItem, createPresenter()) } @Test fun `sets item not selected on detach when this item was selected`() { - whenever(getSelectedItem()).thenReturn(O.just(item)) - - behavior attach view - behavior detach view - - verify(setSelectedItem).invoke(noItem) + testSetsItemNotSelectedOnDetachWhenThisItemWasSelected(item, noItem, createPresenter()) } @Test fun `does not change select state on detach when other item was selected`() { - whenever(getSelectedItem()).thenReturn(O.just(otherItem)) - - behavior attach view - behavior detach view - - verify(setSelectedItem, never()).invoke(any()) + testDoesNotChangeSelectStateOnDetachWhenOtherItemWasSelected(otherItem, noItem, createPresenter()) } @Test fun `does not change select state on detach when nothing was selected`() { - whenever(getSelectedItem()).thenReturn(O.just(noItem)) - - behavior attach view - behavior detach view - - verify(setSelectedItem, never()).invoke(any()) + testDoesNotChangeSelectStateOnDetachWhenNothingWasSelected(noItem, createPresenter()) } @Test fun `shows nothing selected when nothing is selected`() { - whenever(getSelectedItem()).thenReturn(O.just(noItem)) - - behavior attach view - - verify(view).showNothingSelected(item) + testShowsNothingSelectedWhenNothingIsSelected(item, noItem, createPresenter()) } @Test fun `shows other selected when other is selected`() { - whenever(getSelectedItem()).thenReturn(O.just(otherItem)) - - behavior attach view - - verify(view).showOtherSelected(item, otherItem) + testShowsOtherSelectedWhenOtherItemIsSelected(item, otherItem, createPresenter()) } @Test fun `shows this selected when this is selected`() { - whenever(getSelectedItem()).thenReturn(O.just(item)) - - behavior attach view - - verify(view).showThisSelected(item) + testShowsThisSelectedWhenThisItemIsSelected(item, createPresenter()) } - private fun select() = selectsRelay.accept(Unit) + private fun createPresenter(): (() -> O, (String) -> Unit) -> SingleSelectItemBehavior> { + return { get, set -> SingleSelectItemBehavior(item, noItem, get, set, trampolines) } + } +} + +inline fun > testSingleSelectItemBehavior( + item: ITEM, + noItem: ITEM, + otherItem: ITEM, + createPresenter: (() -> O, (ITEM) -> Unit) -> Presenter) { + + testSetsItemSelectedAfterSelectWhenNothingWasSelectedYet(item, noItem, createPresenter) + testSetsItemSelectedAfterSelectWhenOtherItemWasSelected(item, otherItem, createPresenter) + testSetsItemNotSelectedAfterSelectWhenThisItemWasSelected(item, noItem, createPresenter) + testSetsItemNotSelectedOnDetachWhenThisItemWasSelected(item, noItem, createPresenter) + testDoesNotChangeSelectStateOnDetachWhenOtherItemWasSelected(otherItem, noItem, createPresenter) + testDoesNotChangeSelectStateOnDetachWhenNothingWasSelected(noItem, createPresenter) + testShowsNothingSelectedWhenNothingIsSelected(item, noItem, createPresenter) + testShowsOtherSelectedWhenOtherItemIsSelected(item, otherItem, createPresenter) + testShowsThisSelectedWhenThisItemIsSelected(item, createPresenter) +} + +inline fun > testSetsItemSelectedAfterSelectWhenNothingWasSelectedYet( + item: ITEM, + noItem: ITEM, + createPresenter: (() -> O, (ITEM) -> Unit) -> Presenter) { + val getSelectedItem = mock<() -> O>() + val setSelectedItem = mock<(ITEM) -> Unit>() + val selectsRelay = PublishRelay.create() + val presenter = createPresenter(getSelectedItem, setSelectedItem) + val view = view() + whenever(view.selects()).thenReturn(selectsRelay) + whenever(getSelectedItem()).thenReturn(O.just(noItem)) + presenter attach view + + selectsRelay.accept(Unit) + + verify(setSelectedItem).invoke(item) +} + +inline fun > testSetsItemSelectedAfterSelectWhenOtherItemWasSelected( + item: ITEM, + otherItem: ITEM, + createPresenter: (() -> O, (ITEM) -> Unit) -> Presenter) { + val getSelectedItem = mock<() -> O>() + val setSelectedItem = mock<(ITEM) -> Unit>() + val selectsRelay = PublishRelay.create() + val presenter = createPresenter(getSelectedItem, setSelectedItem) + val view = view() + whenever(view.selects()).thenReturn(selectsRelay) + whenever(getSelectedItem()).thenReturn(O.just(otherItem)) + presenter attach view + + selectsRelay.accept(Unit) + + verify(setSelectedItem).invoke(item) +} + +inline fun > testSetsItemNotSelectedAfterSelectWhenThisItemWasSelected( + item: ITEM, + noItem: ITEM, + createPresenter: (() -> O, (ITEM) -> Unit) -> Presenter) { + val getSelectedItem = mock<() -> O>() + val setSelectedItem = mock<(ITEM) -> Unit>() + val selectsRelay = PublishRelay.create() + val presenter = createPresenter(getSelectedItem, setSelectedItem) + val view = view() + whenever(view.selects()).thenReturn(selectsRelay) + whenever(getSelectedItem()).thenReturn(O.just(item)) + presenter attach view + + selectsRelay.accept(Unit) + + verify(setSelectedItem).invoke(noItem) +} + +inline fun > testSetsItemNotSelectedOnDetachWhenThisItemWasSelected( + item: ITEM, + noItem: ITEM, + createPresenter: (() -> O, (ITEM) -> Unit) -> Presenter) { + val getSelectedItem = mock<() -> O>() + val setSelectedItem = mock<(ITEM) -> Unit>() + val presenter = createPresenter(getSelectedItem, setSelectedItem) + val view = view() + whenever(getSelectedItem()).thenReturn(O.just(item)) + + presenter attach view + presenter detach view + + verify(setSelectedItem).invoke(noItem) +} + +inline fun > testDoesNotChangeSelectStateOnDetachWhenOtherItemWasSelected( + otherItem: ITEM, + noItem: ITEM, + createPresenter: (() -> O, (ITEM) -> Unit) -> Presenter) { + val getSelectedItem = mock<() -> O>() + val setSelectedItem = mock<(ITEM) -> Unit>() + val presenter = createPresenter(getSelectedItem, setSelectedItem) + val view = view() + whenever(getSelectedItem()).thenReturn(O.just(otherItem)) + + presenter attach view + presenter detach view + + verify(setSelectedItem, never()).invoke(noItem) +} + +inline fun > testDoesNotChangeSelectStateOnDetachWhenNothingWasSelected( + noItem: ITEM, + createPresenter: (() -> O, (ITEM) -> Unit) -> Presenter) { + val getSelectedItem = mock<() -> O>() + val setSelectedItem = mock<(ITEM) -> Unit>() + val presenter = createPresenter(getSelectedItem, setSelectedItem) + val view = view() + whenever(getSelectedItem()).thenReturn(O.just(noItem)) + + presenter attach view + presenter detach view + + verify(setSelectedItem, never()).invoke(noItem) +} + +inline fun > testShowsNothingSelectedWhenNothingIsSelected( + item: ITEM, + noItem: ITEM, + createPresenter: (() -> O, (ITEM) -> Unit) -> Presenter) { + val getSelectedItem = mock<() -> O>() + val presenter = createPresenter(getSelectedItem, mock()) + val view = view() + whenever(getSelectedItem()).thenReturn(O.just(noItem)) + + presenter attach view + + verify(view).showNothingSelected(item) +} + +inline fun > testShowsOtherSelectedWhenOtherItemIsSelected( + item: ITEM, + otherItem: ITEM, + createPresenter: (() -> O, (ITEM) -> Unit) -> Presenter) { + val getSelectedItem = mock<() -> O>() + val presenter = createPresenter(getSelectedItem, mock()) + val view = view() + whenever(getSelectedItem()).thenReturn(O.just(otherItem)) + + presenter attach view + + verify(view).showOtherSelected(item, otherItem) +} + +inline fun > testShowsThisSelectedWhenThisItemIsSelected( + item: ITEM, + createPresenter: (() -> O, (ITEM) -> Unit) -> Presenter) { + val getSelectedItem = mock<() -> O>() + val presenter = createPresenter(getSelectedItem, mock()) + val view = view() + whenever(getSelectedItem()).thenReturn(O.just(item)) + + presenter attach view + + verify(view).showThisSelected(item) +} + +inline fun > view(): VIEW = mock().apply { + whenever(selects()).thenReturn(Observable.never()) } \ No newline at end of file