diff --git a/store/src/main/java/com/nytimes/android/external/store3/base/impl/MultiParser.kt b/store/src/main/java/com/nytimes/android/external/store3/base/impl/MultiParser.kt index 7af6116..e41d3c2 100644 --- a/store/src/main/java/com/nytimes/android/external/store3/base/impl/MultiParser.kt +++ b/store/src/main/java/com/nytimes/android/external/store3/base/impl/MultiParser.kt @@ -1,40 +1,26 @@ -//package com.nytimes.android.external.store3.base.impl -// -//import com.nytimes.android.external.store3.util.KeyParser -//import com.nytimes.android.external.store3.util.ParserException -// -//import java.util.ArrayList -// -//import io.reactivex.annotations.NonNull -// -//import com.nytimes.android.external.cache3.Preconditions.checkArgument -//import com.nytimes.android.external.cache3.Preconditions.checkNotNull -// -//class MultiParser(parsers: List>) : KeyParser { -// -// private val parsers = ArrayList>() -// -// init { -// this.parsers.addAll(parsers) -// } -// -// private fun createParserException(): ParserException { -// return ParserException("One of the provided parsers has a wrong typing. " + "Make sure that parsers are passed in a correct order and the fromTypes match each other.") -// } -// -// @NonNull -// @Throws(ParserException::class) -// override -// suspend fun apply(@NonNull key: Key, @NonNull raw: Raw): Parsed { -// var parsed: Any = raw!! -// for (parser in parsers) { -// try { -// parsed = parser.apply(key, parsed)!! -// } catch (exception: ClassCastException) { -// throw createParserException() -// } -// -// } -// return parsed as Parsed -// } -//} +package com.nytimes.android.external.store3.base.impl + +import com.nytimes.android.external.store3.util.KeyParser +import com.nytimes.android.external.store3.util.ParserException +import io.reactivex.annotations.NonNull + +class MultiParser(private val parsers: List>) : KeyParser { + + private fun createParserException(): ParserException { + return ParserException("One of the provided parsers has a wrong typing. " + + "Make sure that parsers are passed in a correct order and the fromTypes match each other.") + } + + @NonNull + override suspend fun apply(@NonNull key: Key, @NonNull raw: Raw): Parsed { + var parsed: Any = raw!! + for (parser in parsers) { + try { + parsed = parser.apply(key, parsed)!! + } catch (exception: ClassCastException) { + throw createParserException() + } + } + return parsed as Parsed + } +} diff --git a/store/src/main/java/com/nytimes/android/external/store3/base/impl/ParsingFetcher.kt b/store/src/main/java/com/nytimes/android/external/store3/base/impl/ParsingFetcher.kt index eb9901d..2cc741a 100644 --- a/store/src/main/java/com/nytimes/android/external/store3/base/impl/ParsingFetcher.kt +++ b/store/src/main/java/com/nytimes/android/external/store3/base/impl/ParsingFetcher.kt @@ -10,9 +10,9 @@ import com.nytimes.android.external.store3.base.Parser */ class ParsingFetcher (private val rawFetcher: Fetcher, - private val parser: Parser) { + private val parser: Parser) : Fetcher { - suspend fun fetch(key: Key): Parsed { + override suspend fun fetch(key: Key): Parsed { return rawFetcher.fetch(key).let { parser.apply(it) } } diff --git a/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealStore.kt b/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealStore.kt index 26078ca..8152cf9 100644 --- a/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealStore.kt +++ b/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealStore.kt @@ -9,8 +9,6 @@ import com.nytimes.android.external.store3.util.KeyParser import com.nytimes.android.external.store3.util.NoKeyParser import com.nytimes.android.external.store3.util.NoopParserFunc import com.nytimes.android.external.store3.util.NoopPersister - -import io.reactivex.Maybe import io.reactivex.Observable import io.reactivex.Single import kotlinx.coroutines.channels.ReceiveChannel @@ -38,12 +36,12 @@ open class RealStore : Store { StalePolicy.UNSPECIFIED) } - constructor(fetcher: Fetcher, - persister: Persister, - parser: Parser) { - internalStore = RealInternalStore(fetcher, - persister, - NoKeyParser(parser), + constructor(fetcher: Fetcher<*, Key>, + persister: Persister<*, Key>, + parser: Parser<*, Parsed>) { + internalStore = RealInternalStore(fetcher as Fetcher, + persister as Persister, + NoKeyParser(parser as Parser), StalePolicy.UNSPECIFIED) } @@ -72,7 +70,7 @@ open class RealStore : Store { } fun getWithResult(key: Key): Single> { -TODO("not implemented") + TODO("not implemented") } fun getRefreshing(key: Key): Observable { diff --git a/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealStoreBuilder.kt b/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealStoreBuilder.kt index 5230ff9..adf7976 100644 --- a/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealStoreBuilder.kt +++ b/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealStoreBuilder.kt @@ -6,13 +6,14 @@ import com.nytimes.android.external.store3.util.KeyParser import com.nytimes.android.external.store3.util.NoKeyParser import com.nytimes.android.external.store3.util.NoopParserFunc import com.nytimes.android.external.store3.util.NoopPersister +import java.util.* /** * Builder where there parser is used. */ class RealStoreBuilder { - private var parser: KeyParser? = null + private val parsers = ArrayList>() private var persister: Persister? = null private var fetcher: Fetcher? = null private var memoryPolicy: MemoryPolicy? = null @@ -20,27 +21,24 @@ class RealStoreBuilder { private//remove when it is implemented... var stalePolicy = StalePolicy.UNSPECIFIED - fun fetcher(fetcher: Fetcher): RealStoreBuilder { + fun fetcher(fetcher: Fetcher): RealStoreBuilder = apply { this.fetcher = fetcher - return this } - fun fetcher(fetcher: suspend (Key) -> Raw): RealStoreBuilder { + fun fetcher(fetcher: suspend (Key) -> Raw): RealStoreBuilder = apply { this.fetcher = object : Fetcher { override suspend fun fetch(key: Key): Raw { return fetcher(key) } } - return this } - fun persister(persister: Persister): RealStoreBuilder { + fun persister(persister: Persister): RealStoreBuilder = apply { this.persister = persister - return this } fun persister(diskRead: DiskRead, - diskWrite: DiskWrite): RealStoreBuilder { + diskWrite: DiskWrite): RealStoreBuilder = apply { persister = object : Persister { override suspend fun read(key: Key): Raw? = diskRead.read(key) @@ -48,46 +46,44 @@ class RealStoreBuilder { override suspend fun write(key: Key, raw: Raw): Boolean = diskWrite.write(key, raw) } - return this } - fun parser(parser: Parser): RealStoreBuilder { - this.parser = NoKeyParser(parser) - return this + fun parser(parser: Parser): RealStoreBuilder = apply { + this.parsers.clear() + this.parsers.add(NoKeyParser(parser as Parser)) } - fun parser(parser: KeyParser): RealStoreBuilder { - this.parser = parser + fun parser(parser: suspend (Raw) -> Parsed): RealStoreBuilder = + parser(NoKeyParser(object : Parser { + override suspend fun apply(raw: Raw): Parsed { + return parser(raw) + } + })) - return this + fun parser(parser: KeyParser): RealStoreBuilder = apply { + this.parsers.clear() + this.parsers.add(parser as KeyParser) } - fun parsers(parsers: List>): RealStoreBuilder { - TODO("not implemented") -// this.parsers.clear() -// for (parser in parsers) { -// this.parsers.add(NoKeyParser(parser)) -// } -// return this + fun parsers(parsers: List>): RealStoreBuilder = apply { + this.parsers.clear() + this.parsers.addAll(parsers.map { NoKeyParser(it as Parser) }) } - fun memoryPolicy(memoryPolicy: MemoryPolicy): RealStoreBuilder { + fun memoryPolicy(memoryPolicy: MemoryPolicy): RealStoreBuilder = apply { this.memoryPolicy = memoryPolicy - return this } //Store will backfill the disk cache anytime a record is stale //User will still get the stale record returned to them - fun refreshOnStale(): RealStoreBuilder { + fun refreshOnStale(): RealStoreBuilder = apply { stalePolicy = StalePolicy.REFRESH_ON_STALE - return this } //Store will try to get network source when disk data is stale //if network source throws error or is empty, stale disk data will be returned - fun networkBeforeStale(): RealStoreBuilder { + fun networkBeforeStale(): RealStoreBuilder = apply { stalePolicy = StalePolicy.NETWORK_BEFORE_STALE - return this } fun open(): Store { @@ -95,15 +91,15 @@ class RealStoreBuilder { persister = NoopPersister.create(memoryPolicy) } - if (parser == null) { + if (parsers.isEmpty()) { parser(NoopParserFunc()) } -// val multiParser = MultiParser(parsers) + val multiParser = MultiParser(parsers) - val realInternalStore: InternalStore = RealInternalStore(fetcher!!, persister!!, parser!!, memoryPolicy, stalePolicy) + val realInternalStore: RealInternalStore = RealInternalStore(fetcher!!, persister!!, multiParser, memoryPolicy, stalePolicy) - return RealStore(realInternalStore) + return RealStore(realInternalStore) } companion object { diff --git a/store/src/main/java/com/nytimes/android/external/store3/util/KeyParser.kt b/store/src/main/java/com/nytimes/android/external/store3/util/KeyParser.kt index 477233e..5909e60 100644 --- a/store/src/main/java/com/nytimes/android/external/store3/util/KeyParser.kt +++ b/store/src/main/java/com/nytimes/android/external/store3/util/KeyParser.kt @@ -1,9 +1,8 @@ package com.nytimes.android.external.store3.util import io.reactivex.annotations.NonNull -import io.reactivex.functions.BiFunction -interface KeyParser { +interface KeyParser { @Throws(ParserException::class) suspend fun apply(@NonNull key: Key, @NonNull raw: Raw): Parsed diff --git a/store/src/main/java/com/nytimes/android/external/store3/util/NoKeyParser.kt b/store/src/main/java/com/nytimes/android/external/store3/util/NoKeyParser.kt index 496237a..3754840 100644 --- a/store/src/main/java/com/nytimes/android/external/store3/util/NoKeyParser.kt +++ b/store/src/main/java/com/nytimes/android/external/store3/util/NoKeyParser.kt @@ -4,7 +4,7 @@ import com.nytimes.android.external.store3.base.Parser import io.reactivex.annotations.NonNull -class NoKeyParser(private val parser: Parser) : KeyParser { +class NoKeyParser(private val parser: Parser) : KeyParser { @Throws(ParserException::class) override suspend fun apply(@NonNull key: Key, @NonNull raw: Raw): Parsed { diff --git a/store/src/test/java/com/nytimes/android/external/store3/ClearingPersister.kt b/store/src/test/java/com/nytimes/android/external/store3/ClearingPersister.kt index a6d74c7..7fefb3c 100644 --- a/store/src/test/java/com/nytimes/android/external/store3/ClearingPersister.kt +++ b/store/src/test/java/com/nytimes/android/external/store3/ClearingPersister.kt @@ -4,7 +4,7 @@ import com.nytimes.android.external.store3.base.Clearable import com.nytimes.android.external.store3.base.Persister import com.nytimes.android.external.store3.base.impl.BarCode -class ClearingPersister : Persister, Clearable { +open class ClearingPersister : Persister, Clearable { override suspend fun read(key: BarCode): Int? { throw RuntimeException() } diff --git a/store/src/test/java/com/nytimes/android/external/store3/DontCacheErrorsTest1.kt b/store/src/test/java/com/nytimes/android/external/store3/DontCacheErrorsTest1.kt index 5bcc7db..07bd442 100644 --- a/store/src/test/java/com/nytimes/android/external/store3/DontCacheErrorsTest1.kt +++ b/store/src/test/java/com/nytimes/android/external/store3/DontCacheErrorsTest1.kt @@ -36,7 +36,8 @@ class DontCacheErrorsTest { try { store.get(barcode) fail() - } catch (e: Exception) { + } catch (e: RuntimeException) { + e.printStackTrace() } shouldThrow = false diff --git a/store/src/test/java/com/nytimes/android/external/store3/StoreBuilderTest.java b/store/src/test/java/com/nytimes/android/external/store3/StoreBuilderTest.java deleted file mode 100644 index 70d854a..0000000 --- a/store/src/test/java/com/nytimes/android/external/store3/StoreBuilderTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.nytimes.android.external.store3; - - -import com.nytimes.android.external.store3.base.Fetcher; -import com.nytimes.android.external.store3.base.Persister; -import com.nytimes.android.external.store3.base.impl.BarCode; -import com.nytimes.android.external.store3.base.impl.Store; -import com.nytimes.android.external.store3.base.impl.StoreBuilder; - -import org.junit.Test; - -import java.util.Date; - -import javax.annotation.Nonnull; - -import io.reactivex.Maybe; -import io.reactivex.Single; - -import static org.assertj.core.api.Assertions.assertThat; - -public class StoreBuilderTest { - - public static final Date DATE = new Date(); - - @Test - public void testBuildersBuildWithCorrectTypes() { - //test is checking whether types are correct in builders - Store store = StoreBuilder.parsedWithKey() - .fetcher(key -> Single.just(String.valueOf(key))) - .persister(new Persister() { - @Nonnull - @Override - public Maybe read(@Nonnull Integer key) { - return Maybe.just(String.valueOf(key)); - } - - @Nonnull - @Override - public Single write(@Nonnull Integer key, @Nonnull String s) { - return Single.just(true); - } - }) - .parser(s -> DATE) - .open(); - - - Store barCodeStore = StoreBuilder.barcode().fetcher(new Fetcher() { - @Nonnull - @Override - public Single fetch(@Nonnull BarCode barCode) { - return Single.just(DATE); - } - }).open(); - - - Store keyStore = StoreBuilder.key() - .fetcher(new Fetcher() { - @Nonnull - @Override - public Single fetch(@Nonnull Integer key) { - return Single.just(DATE); - } - }) - .open(); - Date result = store.get(5).blockingGet(); - result = barCodeStore.get(new BarCode("test", "5")).blockingGet(); - result = keyStore.get(5).blockingGet(); - assertThat(result).isNotNull(); - - } -} diff --git a/store/src/test/java/com/nytimes/android/external/store3/StoreBuilderTest.kt b/store/src/test/java/com/nytimes/android/external/store3/StoreBuilderTest.kt new file mode 100644 index 0000000..b1aa6a4 --- /dev/null +++ b/store/src/test/java/com/nytimes/android/external/store3/StoreBuilderTest.kt @@ -0,0 +1,47 @@ +package com.nytimes.android.external.store3 + + +import com.nytimes.android.external.store3.base.Persister +import com.nytimes.android.external.store3.base.impl.BarCode +import com.nytimes.android.external.store3.base.impl.StoreBuilder +import kotlinx.coroutines.runBlocking +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import java.util.* + +class StoreBuilderTest { + + @Test + fun testBuildersBuildWithCorrectTypes() = runBlocking { + //test is checking whether types are correct in builders + val store = StoreBuilder.parsedWithKey() + .fetcher { key -> key.toString() } + .persister(object : Persister { + override suspend fun read(key: Int): String? { + return key.toString() + } + + override suspend fun write(key: Int, raw: String) = true + }) + .parser { DATE } + .open() + + + val barCodeStore = StoreBuilder.barcode().fetcher { DATE }.open() + + + val keyStore = StoreBuilder.key() + .fetcher { DATE } + .open() + var result = store.get(5) + result = barCodeStore.get(BarCode("test", "5")) + result = keyStore.get(5) + assertThat(result).isNotNull() + + } + + companion object { + + val DATE = Date() + } +} diff --git a/store/src/test/java/com/nytimes/android/external/store3/StoreTest.kt b/store/src/test/java/com/nytimes/android/external/store3/StoreTest.kt index 2cfde44..5cdf080 100644 --- a/store/src/test/java/com/nytimes/android/external/store3/StoreTest.kt +++ b/store/src/test/java/com/nytimes/android/external/store3/StoreTest.kt @@ -1,13 +1,13 @@ package com.nytimes.android.external.store3 import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever import com.nytimes.android.external.cache3.CacheBuilder import com.nytimes.android.external.store3.base.Fetcher import com.nytimes.android.external.store3.base.Persister import com.nytimes.android.external.store3.base.impl.BarCode import com.nytimes.android.external.store3.base.impl.StoreBuilder import com.nytimes.android.external.store3.util.NoopPersister -import io.reactivex.Maybe import io.reactivex.Single import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking @@ -32,15 +32,15 @@ class StoreTest { .open() - `when`(fetcher.fetch(barCode)) - .thenReturn(Single.just(NETWORK)) + whenever(fetcher.fetch(barCode)) + .thenReturn(NETWORK) - `when`(persister.read(barCode)) - .thenReturn(Maybe.empty()) - .thenReturn(Maybe.just(DISK)) + whenever(persister.read(barCode)) + .thenReturn(null) + .thenReturn(DISK) - `when`(persister.write(barCode, NETWORK)) - .thenReturn(Single.just(true)) + whenever(persister.write(barCode, NETWORK)) + .thenReturn(true) var value = simpleStore.get(barCode) @@ -59,15 +59,15 @@ class StoreTest { // .open() // // -// `when`(fetcher.fetch(barCode)) -// .thenReturn(Single.just(NETWORK)) +// whenever(fetcher.fetch(barCode)) +// .thenReturn(NETWORK) // -// `when`(persister.read(barCode)) -// .thenReturn(Maybe.empty()) -// .thenReturn(Maybe.just(DISK)) +// whenever(persister.read(barCode)) +// .thenReturn(null) +// .thenReturn(DISK) // -// `when`(persister.write(barCode, NETWORK)) -// .thenReturn(Single.just(true)) +// whenever(persister.write(barCode, NETWORK)) +// .thenReturn(true) // // var result = simpleStore.getWithResult(barCode) // @@ -90,23 +90,24 @@ class StoreTest { .open() val networkSingle = Single.create { emitter -> - if (counter.incrementAndGet() == 1) { - emitter.onSuccess(NETWORK) - } else { - emitter.onError(RuntimeException("Yo Dawg your inflight is broken")) - } } - `when`(fetcher.fetch(barCode)) - .thenReturn(networkSingle) + whenever(fetcher.fetch(barCode)) + .thenAnswer { + if (counter.incrementAndGet() == 1) { + NETWORK + } else { + throw RuntimeException("Yo Dawg your inflight is broken") + } + } - `when`(persister.read(barCode)) - .thenReturn(Maybe.empty()) - .thenReturn(Maybe.just(DISK)) + whenever(persister.read(barCode)) + .thenReturn(null) + .thenReturn(DISK) - `when`(persister.write(barCode, NETWORK)) - .thenReturn(Single.just(true)) + whenever(persister.write(barCode, NETWORK)) + .thenReturn(true) val deferred = async { simpleStore.get(barCode) } @@ -133,15 +134,15 @@ class StoreTest { // } // // -// `when`(fetcher.fetch(barCode)) +// whenever(fetcher.fetch(barCode)) // .thenReturn(networkSingle) // -// `when`(persister.read(barCode)) -// .thenReturn(Maybe.empty()) -// .thenReturn(Maybe.just(DISK)) +// whenever(persister.read(barCode)) +// .thenReturn(null) +// .thenReturn(DISK) // -// `when`(persister.write(barCode, NETWORK)) -// .thenReturn(Single.just(true)) +// whenever(persister.write(barCode, NETWORK)) +// .thenReturn(true) // // // val response = simpleStore.getWithResult(barCode) @@ -160,13 +161,13 @@ class StoreTest { val simpleStore = SampleStore(fetcher, persister) simpleStore.clear() - `when`(fetcher.fetch(barCode)) - .thenReturn(Single.just(NETWORK)) + whenever(fetcher.fetch(barCode)) + .thenReturn(NETWORK) - `when`(persister.read(barCode)) - .thenReturn(Maybe.empty()) - .thenReturn(Maybe.just(DISK)) - `when`(persister.write(barCode, NETWORK)).thenReturn(Single.just(true)) + whenever(persister.read(barCode)) + .thenReturn(null) + .thenReturn(DISK) + whenever(persister.write(barCode, NETWORK)).thenReturn(true) var value = simpleStore.get(barCode) assertThat(value).isEqualTo(DISK) @@ -181,13 +182,13 @@ class StoreTest { // val simpleStore = SampleStore(fetcher, persister) // simpleStore.clear() // -// `when`(fetcher.fetch(barCode)) -// .thenReturn(Single.just(NETWORK)) +// whenever(fetcher.fetch(barCode)) +// .thenReturn(NETWORK) // -// `when`(persister.read(barCode)) -// .thenReturn(Maybe.empty()) -// .thenReturn(Maybe.just(DISK)) -// `when`(persister.write(barCode, NETWORK)).thenReturn(Single.just(true)) +// whenever(persister.read(barCode)) +// .thenReturn(null) +// .thenReturn(DISK) +// whenever(persister.write(barCode, NETWORK)).thenReturn(true) // // var result = simpleStore.getWithResult(barCode) // @@ -207,8 +208,8 @@ class StoreTest { val simpleStore = SampleStore(fetcher, persister) - `when`(fetcher.fetch(barCode)) - .thenReturn(Single.just(NETWORK)) + whenever(fetcher.fetch(barCode)) + .thenReturn(NETWORK) var value = simpleStore.get(barCode) verify>(fetcher, times(1)).fetch(barCode) @@ -232,8 +233,8 @@ class StoreTest { // val simpleStore = SampleStore(fetcher, persister) // // -// `when`(fetcher.fetch(barCode)) -// .thenReturn(Single.just(NETWORK)) +// whenever(fetcher.fetch(barCode)) +// .thenReturn(NETWORK) // // var value = simpleStore.getWithResult(barCode) // verify>(fetcher, times(1)).fetch(barCode) diff --git a/store/src/test/java/com/nytimes/android/external/store3/StoreWithParserTest.kt b/store/src/test/java/com/nytimes/android/external/store3/StoreWithParserTest.kt index ba0f6a5..5b3f88a 100644 --- a/store/src/test/java/com/nytimes/android/external/store3/StoreWithParserTest.kt +++ b/store/src/test/java/com/nytimes/android/external/store3/StoreWithParserTest.kt @@ -1,6 +1,6 @@ package com.nytimes.android.external.store3 -import com.nytimes.android.external.store.util.Result +import com.nhaarman.mockitokotlin2.mock import com.nytimes.android.external.store3.base.Fetcher import com.nytimes.android.external.store3.base.Parser import com.nytimes.android.external.store3.base.Persister @@ -8,141 +8,128 @@ import com.nytimes.android.external.store3.base.impl.BarCode import com.nytimes.android.external.store3.base.impl.ParsingStoreBuilder import io.reactivex.Maybe import io.reactivex.Single +import kotlinx.coroutines.runBlocking import org.assertj.core.api.Assertions.assertThat import org.junit.Test -import org.mockito.Mock import org.mockito.Mockito.* import org.mockito.MockitoAnnotations class StoreWithParserTest { - @Mock - internal var fetcher: Fetcher? = null - @Mock - internal var persister: Persister? = null - @Mock - internal var parser: Parser? = null + val fetcher: Fetcher = mock() + val persister: Persister = mock() + val parser: Parser = mock() private val barCode = BarCode("key", "value") @Test - @Throws(Exception::class) - fun testSimple() { - MockitoAnnotations.initMocks(this) - - + fun testSimple() = runBlocking { val simpleStore = ParsingStoreBuilder.builder() - .persister(persister!!) - .fetcher(fetcher!!) - .parser(parser!!) + .persister(persister) + .fetcher(fetcher) + .parser(parser) .open() - `when`(fetcher!!.fetch(barCode)) + `when`(fetcher.fetch(barCode)) .thenReturn(Single.just(NETWORK)) - `when`(persister!!.read(barCode)) + `when`(persister.read(barCode)) .thenReturn(Maybe.empty()) .thenReturn(Maybe.just(DISK)) - `when`(persister!!.write(barCode, NETWORK)) + `when`(persister.write(barCode, NETWORK)) .thenReturn(Single.just(true)) - `when`(parser!!.apply(DISK)).thenReturn(barCode.key) + `when`(parser.apply(DISK)).thenReturn(barCode.key) - var value = simpleStore.get(barCode).blockingGet() + var value = simpleStore.get(barCode) assertThat(value).isEqualTo(barCode.key) - value = simpleStore.get(barCode).blockingGet() + value = simpleStore.get(barCode) assertThat(value).isEqualTo(barCode.key) verify>(fetcher, times(1)).fetch(barCode) } +// @Test +// fun testSimpleWithResult() = runBlocking { +// val simpleStore = ParsingStoreBuilder.builder() +// .persister(persister) +// .fetcher(fetcher) +// .parser(parser) +// .open() +// +// `when`(fetcher.fetch(barCode)) +// .thenReturn(Single.just(NETWORK)) +// +// `when`(persister.read(barCode)) +// .thenReturn(Maybe.empty()) +// .thenReturn(Maybe.just(DISK)) +// +// `when`(persister.write(barCode, NETWORK)) +// .thenReturn(Single.just(true)) +// +// `when`(parser.apply(DISK)).thenReturn(barCode.key) +// +// var result = simpleStore.getWithResult(barCode) +// assertThat(result.source()).isEqualTo(Result.Source.NETWORK) +// assertThat(result.value()).isEqualTo(barCode.key) +// +// result = simpleStore.getWithResult(barCode) +// assertThat(result.source()).isEqualTo(Result.Source.CACHE) +// assertThat(result.value()).isEqualTo(barCode.key) +// verify>(fetcher, times(1)).fetch(barCode) +// } + @Test - @Throws(Exception::class) - fun testSimpleWithResult() { + fun testSubclass() = runBlocking { MockitoAnnotations.initMocks(this) + val simpleStore = SampleParsingStore(fetcher, persister, parser) - val simpleStore = ParsingStoreBuilder.builder() - .persister(persister!!) - .fetcher(fetcher!!) - .parser(parser!!) - .open() - - `when`(fetcher!!.fetch(barCode)) + `when`(fetcher.fetch(barCode)) .thenReturn(Single.just(NETWORK)) - `when`(persister!!.read(barCode)) + `when`(persister.read(barCode)) .thenReturn(Maybe.empty()) .thenReturn(Maybe.just(DISK)) - `when`(persister!!.write(barCode, NETWORK)) + `when`(persister.write(barCode, NETWORK)) .thenReturn(Single.just(true)) - `when`(parser!!.apply(DISK)).thenReturn(barCode.key) + `when`(parser.apply(DISK)).thenReturn(barCode.key) - var result = simpleStore.getWithResult(barCode).blockingGet() - assertThat(result.source()).isEqualTo(Result.Source.NETWORK) - assertThat(result.value()).isEqualTo(barCode.key) - - result = simpleStore.getWithResult(barCode).blockingGet() - assertThat(result.source()).isEqualTo(Result.Source.CACHE) - assertThat(result.value()).isEqualTo(barCode.key) - verify>(fetcher, times(1)).fetch(barCode) - } - - @Test - @Throws(Exception::class) - fun testSubclass() { - MockitoAnnotations.initMocks(this) - - val simpleStore = SampleParsingStore(fetcher!!, persister!!, parser!!) - - `when`(fetcher!!.fetch(barCode)) - .thenReturn(Single.just(NETWORK)) - - `when`(persister!!.read(barCode)) - .thenReturn(Maybe.empty()) - .thenReturn(Maybe.just(DISK)) - - `when`(persister!!.write(barCode, NETWORK)) - .thenReturn(Single.just(true)) - - `when`(parser!!.apply(DISK)).thenReturn(barCode.key) - - var value = simpleStore.get(barCode).blockingGet() + var value = simpleStore.get(barCode) assertThat(value).isEqualTo(barCode.key) - value = simpleStore.get(barCode).blockingGet() + value = simpleStore.get(barCode) assertThat(value).isEqualTo(barCode.key) verify>(fetcher, times(1)).fetch(barCode) } - @Test - @Throws(Exception::class) - fun testSubclassWithResult() { - MockitoAnnotations.initMocks(this) - - val simpleStore = SampleParsingStore(fetcher!!, persister!!, parser!!) - - `when`(fetcher!!.fetch(barCode)) - .thenReturn(Single.just(NETWORK)) - - `when`(persister!!.read(barCode)) - .thenReturn(Maybe.empty()) - .thenReturn(Maybe.just(DISK)) - - `when`(persister!!.write(barCode, NETWORK)) - .thenReturn(Single.just(true)) - - `when`(parser!!.apply(DISK)).thenReturn(barCode.key) - - var result = simpleStore.getWithResult(barCode).blockingGet() - assertThat(result.source()).isEqualTo(Result.Source.NETWORK) - assertThat(result.value()).isEqualTo(barCode.key) - - result = simpleStore.getWithResult(barCode).blockingGet() - assertThat(result.source()).isEqualTo(Result.Source.CACHE) - assertThat(result.value()).isEqualTo(barCode.key) - verify>(fetcher, times(1)).fetch(barCode) - } +// @Test +// fun testSubclassWithResult() = runBlocking { +// MockitoAnnotations.initMocks(this) +// +// val simpleStore = SampleParsingStore(fetcher, persister, parser) +// +// `when`(fetcher.fetch(barCode)) +// .thenReturn(Single.just(NETWORK)) +// +// `when`(persister.read(barCode)) +// .thenReturn(Maybe.empty()) +// .thenReturn(Maybe.just(DISK)) +// +// `when`(persister.write(barCode, NETWORK)) +// .thenReturn(Single.just(true)) +// +// `when`(parser.apply(DISK)).thenReturn(barCode.key) +// +// var result = simpleStore.getWithResult(barCode) +// assertThat(result.source()).isEqualTo(Result.Source.NETWORK) +// assertThat(result.value()).isEqualTo(barCode.key) +// +// result = simpleStore.getWithResult(barCode) +// assertThat(result.source()).isEqualTo(Result.Source.CACHE) +// assertThat(result.value()).isEqualTo(barCode.key) +// verify>(fetcher, times(1)).fetch(barCode) +// } companion object { diff --git a/store/src/test/java/com/nytimes/android/external/store3/StreamOneKeyTest.java b/store/src/test/java/com/nytimes/android/external/store3/StreamOneKeyTest.java deleted file mode 100644 index e0299e6..0000000 --- a/store/src/test/java/com/nytimes/android/external/store3/StreamOneKeyTest.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.nytimes.android.external.store3; - -import com.nytimes.android.external.store3.base.Fetcher; -import com.nytimes.android.external.store3.base.Persister; -import com.nytimes.android.external.store3.base.impl.BarCode; -import com.nytimes.android.external.store3.base.impl.Store; -import com.nytimes.android.external.store3.base.impl.StoreBuilder; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.runners.MockitoJUnitRunner; - -import io.reactivex.Maybe; -import io.reactivex.Single; -import io.reactivex.observers.TestObserver; - -import static org.mockito.Mockito.when; - -@RunWith(MockitoJUnitRunner.class) -public class StreamOneKeyTest { - - private static final String TEST_ITEM = "test"; - private static final String TEST_ITEM2 = "test2"; - - @Mock - Fetcher fetcher; - @Mock - Persister persister; - - private final BarCode barCode = new BarCode("key", "value"); - private final BarCode barCode2 = new BarCode("key2", "value2"); - - private Store store; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - store = StoreBuilder.barcode() - .persister(persister) - .fetcher(fetcher) - .open(); - - when(fetcher.fetch(barCode)) - .thenReturn(Single.just(TEST_ITEM)) - .thenReturn(Single.just(TEST_ITEM2)); - - when(persister.read(barCode)) - .thenReturn(Maybe.empty()) - .thenReturn(Maybe.just(TEST_ITEM)) - .thenReturn(Maybe.just(TEST_ITEM2)); - - when(persister.write(barCode, TEST_ITEM)) - .thenReturn(Single.just(true)); - when(persister.write(barCode, TEST_ITEM2)) - .thenReturn(Single.just(true)); - } - - @Test - public void testStream() { - TestObserver streamObservable = store.stream(barCode).test(); - //first time we subscribe to stream it will fail getting from memory & disk and instead - //fresh from network, write to disk and notifiy subscribers - streamObservable.assertValueCount(1); - - store.clear(); - //fresh should notify subscribers again - store.fresh(barCode).test().awaitCount(1); - streamObservable.assertValues(TEST_ITEM, TEST_ITEM2); - - //get for another barcode should not trigger a stream for barcode1 - when(fetcher.fetch(barCode2)) - .thenReturn(Single.just(TEST_ITEM)); - when(persister.read(barCode2)) - .thenReturn(Maybe.empty()) - .thenReturn(Maybe.just(TEST_ITEM)); - when(persister.write(barCode2, TEST_ITEM)) - .thenReturn(Single.just(true)); - store.get(barCode2).test().awaitCount(1); - streamObservable.assertValueCount(2); - } -} diff --git a/store/src/test/java/com/nytimes/android/external/store3/StreamOneKeyTest.kt b/store/src/test/java/com/nytimes/android/external/store3/StreamOneKeyTest.kt new file mode 100644 index 0000000..9e525c7 --- /dev/null +++ b/store/src/test/java/com/nytimes/android/external/store3/StreamOneKeyTest.kt @@ -0,0 +1,75 @@ +package com.nytimes.android.external.store3 + +import com.nhaarman.mockitokotlin2.mock +import com.nytimes.android.external.store3.base.Fetcher +import com.nytimes.android.external.store3.base.Persister +import com.nytimes.android.external.store3.base.impl.BarCode +import com.nytimes.android.external.store3.base.impl.Store +import com.nytimes.android.external.store3.base.impl.StoreBuilder +import io.reactivex.Maybe +import io.reactivex.Single +import kotlinx.coroutines.runBlocking +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.`when` + +class StreamOneKeyTest { + + val fetcher: Fetcher = mock() + val persister: Persister = mock() + + private val barCode = BarCode("key", "value") + private val barCode2 = BarCode("key2", "value2") + + private val store: Store = StoreBuilder.barcode() + .persister(persister) + .fetcher(fetcher) + .open() + + @Before + fun setUp() = runBlocking { + `when`(fetcher.fetch(barCode)) + .thenReturn(Single.just(TEST_ITEM)) + .thenReturn(Single.just(TEST_ITEM2)) + + `when`(persister.read(barCode)) + .thenReturn(Maybe.empty()) + .thenReturn(Maybe.just(TEST_ITEM)) + .thenReturn(Maybe.just(TEST_ITEM2)) + + `when`(persister.write(barCode, TEST_ITEM)) + .thenReturn(Single.just(true)) + `when`(persister.write(barCode, TEST_ITEM2)) + .thenReturn(Single.just(true)) + } + + @Test + fun testStream() = runBlocking { + val streamObservable = store.stream(barCode).test() + //first time we subscribe to stream it will fail getting from memory & disk and instead + //fresh from network, write to disk and notifiy subscribers + streamObservable.assertValueCount(1) + + store.clear() + //fresh should notify subscribers again + store.fresh(barCode) + streamObservable.assertValues(TEST_ITEM, TEST_ITEM2) + + //get for another barcode should not trigger a stream for barcode1 + `when`(fetcher.fetch(barCode2)) + .thenReturn(Single.just(TEST_ITEM)) + `when`(persister.read(barCode2)) + .thenReturn(Maybe.empty()) + .thenReturn(Maybe.just(TEST_ITEM)) + `when`(persister.write(barCode2, TEST_ITEM)) + .thenReturn(Single.just(true)) + store.get(barCode2) + streamObservable.assertValueCount(2) + } + + companion object { + + private val TEST_ITEM = "test" + private val TEST_ITEM2 = "test2" + } +} diff --git a/store/src/test/java/com/nytimes/android/external/store3/room/ClearStoreRoomTest.kt b/store/src/test/java/com/nytimes/android/external/store3/room/ClearStoreRoomTest.kt index c44b776..413a56f 100644 --- a/store/src/test/java/com/nytimes/android/external/store3/room/ClearStoreRoomTest.kt +++ b/store/src/test/java/com/nytimes/android/external/store3/room/ClearStoreRoomTest.kt @@ -1,5 +1,6 @@ package com.nytimes.android.external.store3.room +import com.nhaarman.mockitokotlin2.mock import com.nytimes.android.external.store3.base.Clearable import com.nytimes.android.external.store3.base.impl.BarCode import com.nytimes.android.external.store3.base.impl.StalePolicy @@ -8,16 +9,14 @@ import com.nytimes.android.external.store3.base.room.RoomPersister import io.reactivex.Observable import org.assertj.core.api.Assertions.assertThat import org.junit.Test -import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.Mockito.verify import java.util.concurrent.atomic.AtomicInteger class ClearStoreRoomTest { - @Mock - internal var persister: RoomClearingPersister? = null + private val persister: RoomClearingPersister = mock() private val networkCalls: AtomicInteger = AtomicInteger(0) - private var store = StoreRoom.from({ Observable.fromCallable { networkCalls.incrementAndGet() } }, + private val store = StoreRoom.from({ Observable.fromCallable { networkCalls.incrementAndGet() } }, persister, StalePolicy.UNSPECIFIED) @@ -26,18 +25,18 @@ class ClearStoreRoomTest { // one request should produce one call val barcode = BarCode("type", "key") - `when`(persister!!.read(barcode)) + `when`(persister.read(barcode)) .thenReturn(Observable.empty()) //read from disk on get .thenReturn(Observable.just(1)) //read from disk after fetching from network .thenReturn(Observable.empty()) //read from disk after clearing .thenReturn(Observable.just(1)) //read from disk after making additional network call - store!!.get(barcode).test().awaitTerminalEvent() + store.get(barcode).test().awaitTerminalEvent() assertThat(networkCalls.toInt()).isEqualTo(1) // after clearing the memory another call should be made - store!!.clear(barcode) - store!!.get(barcode).test().awaitTerminalEvent() + store.clear(barcode) + store.get(barcode).test().awaitTerminalEvent() verify(persister).clear(barcode) assertThat(networkCalls.toInt()).isEqualTo(2) } @@ -47,13 +46,13 @@ class ClearStoreRoomTest { val barcode1 = BarCode("type1", "key1") val barcode2 = BarCode("type2", "key2") - `when`(persister!!.read(barcode1)) + `when`(persister.read(barcode1)) .thenReturn(Observable.empty()) //read from disk .thenReturn(Observable.just(1)) //read from disk after fetching from network .thenReturn(Observable.empty()) //read from disk after clearing disk cache .thenReturn(Observable.just(1)) //read from disk after making additional network call - `when`(persister!!.read(barcode2)) + `when`(persister.read(barcode2)) .thenReturn(Observable.empty()) //read from disk .thenReturn(Observable.just(1)) //read from disk after fetching from network .thenReturn(Observable.empty()) //read from disk after clearing disk cache @@ -61,20 +60,20 @@ class ClearStoreRoomTest { // each request should produce one call - store!!.get(barcode1).test().awaitTerminalEvent() - store!!.get(barcode2).test().awaitTerminalEvent() + store.get(barcode1).test().awaitTerminalEvent() + store.get(barcode2).test().awaitTerminalEvent() assertThat(networkCalls.toInt()).isEqualTo(2) - store!!.clear() + store.clear() // after everything is cleared each request should produce another 2 calls - store!!.get(barcode1).test().awaitTerminalEvent() - store!!.get(barcode2).test().awaitTerminalEvent() + store.get(barcode1).test().awaitTerminalEvent() + store.get(barcode2).test().awaitTerminalEvent() assertThat(networkCalls.toInt()).isEqualTo(4) } //everything will be mocked - internal class RoomClearingPersister : RoomPersister, Clearable { + internal open class RoomClearingPersister : RoomPersister, Clearable { override fun clear(key: BarCode) { throw RuntimeException() } diff --git a/store/src/test/java/com/nytimes/android/external/store3/util/NoopPersisterTest.kt b/store/src/test/java/com/nytimes/android/external/store3/util/NoopPersisterTest.kt index 489a7e1..e726a6f 100644 --- a/store/src/test/java/com/nytimes/android/external/store3/util/NoopPersisterTest.kt +++ b/store/src/test/java/com/nytimes/android/external/store3/util/NoopPersisterTest.kt @@ -11,7 +11,7 @@ import java.util.concurrent.TimeUnit class NoopPersisterTest { - @Rule + @get:Rule var exception = ExpectedException.none() @Test