Skip to content

Commit

Permalink
Merge pull request #13 from mvarnagiris/memory_cache
Browse files Browse the repository at this point in the history
Memory cache
  • Loading branch information
mvarnagiris authored Mar 12, 2018
2 parents 241ac7e + 8673e2d commit 45821af
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/main/kotlin/com/mvcoding/mvp/DataSource.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.mvcoding.mvp

interface DataSource<DATA> {
fun data(): O<DATA>
}
10 changes: 10 additions & 0 deletions src/main/kotlin/com/mvcoding/mvp/data/FunctionDataSource.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.mvcoding.mvp.data

import com.mvcoding.mvp.DataSource
import com.mvcoding.mvp.O

class FunctionDataSource<DATA>(private val dataSource: () -> O<DATA>) : DataSource<DATA> {
override fun data(): O<DATA> = dataSource()
}

fun <DATA> (() -> O<DATA>).dataSource() = FunctionDataSource(this)
15 changes: 15 additions & 0 deletions src/main/kotlin/com/mvcoding/mvp/data/MemoryDataSource.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.mvcoding.mvp.data

import com.mvcoding.mvp.DataSource
import com.mvcoding.mvp.O

class MemoryDataSource<DATA>(dataSource: DataSource<DATA>) : DataSource<DATA> {
constructor(dataSource: () -> O<DATA>) : this(dataSource.dataSource())

private val observable by lazy { dataSource.data().replay(1).autoConnect() }

override fun data(): O<DATA> = observable
}

fun <DATA> DataSource<DATA>.memoryDataSource() = MemoryDataSource(this)
fun <DATA> (() -> O<DATA>).memoryDataSource() = MemoryDataSource(this)
72 changes: 72 additions & 0 deletions src/test/kotlin/com/mvcoding/mvp/data/MemoryDataSourceTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.mvcoding.mvp.data

import com.jakewharton.rxrelay2.PublishRelay
import com.mvcoding.mvp.DataSource
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.times
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import io.reactivex.observers.TestObserver
import org.junit.Test

class MemoryDataSourceTest {

@Test
fun `upstream DataSource is called only once and cached data is returned to other observers`() {
testUpstreamDataSourceIsCalledOnlyOnceAndCachedDataIsReturnedToOtherObservers(1) { it.memoryDataSource() }
}

@Test
fun `returns data to late observers when initial observers are disposed before data is delivered`() {
testReturnsDataToLateObserversWhenInitialObserversAreDisposedBeforeDataIsDelivered(1) { it.memoryDataSource() }
}
}

fun <DATA> testMemoryDataSource(data: DATA, createDataSource: (DataSource<DATA>) -> DataSource<DATA>) {
testUpstreamDataSourceIsCalledOnlyOnceAndCachedDataIsReturnedToOtherObservers(data, createDataSource)
testReturnsDataToLateObserversWhenInitialObserversAreDisposedBeforeDataIsDelivered(data, createDataSource)
}

private fun <DATA> testUpstreamDataSourceIsCalledOnlyOnceAndCachedDataIsReturnedToOtherObservers(
data: DATA,
createDataSource: (DataSource<DATA>) -> DataSource<DATA>) {

val initialObserver1 = TestObserver.create<DATA>()
val initialObserver2 = TestObserver.create<DATA>()
val otherObserver = TestObserver.create<DATA>()
val relay = PublishRelay.create<DATA>()
val upstreamDataSource = mock<DataSource<DATA>>()
val dataSource = createDataSource(upstreamDataSource)
whenever(upstreamDataSource.data()).thenReturn(relay)

dataSource.data().subscribe(initialObserver1)
dataSource.data().subscribe(initialObserver2)
relay.accept(data)
dataSource.data().subscribe(otherObserver)

initialObserver1.assertValue(data)
initialObserver2.assertValue(data)
otherObserver.assertValue(data)
verify(upstreamDataSource, times(1)).data()
}

private fun <DATA> testReturnsDataToLateObserversWhenInitialObserversAreDisposedBeforeDataIsDelivered(
data: DATA,
createDataSource: (DataSource<DATA>) -> DataSource<DATA>) {

val initialObserver = TestObserver.create<DATA>()
val otherObserver = TestObserver.create<DATA>()
val relay = PublishRelay.create<DATA>()
val upstreamDataSource = mock<DataSource<DATA>>()
val dataSource = createDataSource(upstreamDataSource)
whenever(upstreamDataSource.data()).thenReturn(relay)

dataSource.data().subscribe(initialObserver)
initialObserver.dispose()
relay.accept(data)
dataSource.data().subscribe(otherObserver)

initialObserver.assertNoValues()
otherObserver.assertValue(data)
verify(upstreamDataSource, times(1)).data()
}

0 comments on commit 45821af

Please sign in to comment.