From 10d0cf6d07e33fe8d5261b754265a0f0545b2b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Antonio=20D=C3=ADaz-Benito=20Soriano?= Date: Fri, 23 Jun 2017 03:22:34 +0200 Subject: [PATCH] Add store-kotlin module (#229) * Add store-kotlin module * Remove useless file * Fix package in AndroidManifest * Refactor module tests to assertJ * Remove wrong annotation * Add store-kotlin artifact to README * Add module README * Add KDoc to Javadoc jar * Add Experimental annotation * Mark all public store-kotlin classes as @Experimental * Replace use of rx's @Experimental with local one instead --- README.md | 5 ++ build.gradle | 6 ++ buildsystem/dependencies.gradle | 5 +- gradle/maven-push.gradle | 14 +++- .../jackson/JacksonTransformerFactory.java | 3 +- .../moshi/MoshiTransformerFactory.java | 3 +- .../middleware/GsonTransformerFactory.java | 3 +- settings.gradle | 2 +- store-kotlin/README.md | 40 +++++++++++ store-kotlin/build.gradle | 26 +++++++ store-kotlin/gradle.properties | 3 + store-kotlin/src/main/AndroidManifest.xml | 3 + .../base/impl/FluentMemoryPolicyBuilder.kt | 31 +++++++++ .../base/impl/FluentRealStoreBuilder.kt | 46 +++++++++++++ .../store3/base/impl/FluentStoreBuilder.kt | 60 +++++++++++++++++ .../base/impl/MemoryPolicyParameters.kt | 22 ++++++ .../store3/base/impl/StoreParameters.kt | 41 ++++++++++++ .../impl/FluentMemoryPolicyBuilderSpec.kt | 50 ++++++++++++++ .../base/impl/FluentRealStoreBuilderSpec.kt | 43 ++++++++++++ .../base/impl/FluentStoreBuilderSpec.kt | 47 +++++++++++++ .../base/impl/MemoryPolicyParametersSpec.kt | 67 +++++++++++++++++++ .../store3/base/impl/StoreParametersSpec.kt | 66 ++++++++++++++++++ .../store3/annotations/Experimental.java | 8 +++ .../store3/base/impl/RealInternalStore.java | 2 +- .../external/store3/base/impl/Store.java | 3 +- 25 files changed, 586 insertions(+), 13 deletions(-) create mode 100644 store-kotlin/README.md create mode 100644 store-kotlin/build.gradle create mode 100644 store-kotlin/gradle.properties create mode 100644 store-kotlin/src/main/AndroidManifest.xml create mode 100644 store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentMemoryPolicyBuilder.kt create mode 100644 store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentRealStoreBuilder.kt create mode 100644 store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentStoreBuilder.kt create mode 100644 store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/MemoryPolicyParameters.kt create mode 100644 store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/StoreParameters.kt create mode 100644 store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentMemoryPolicyBuilderSpec.kt create mode 100644 store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentRealStoreBuilderSpec.kt create mode 100644 store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentStoreBuilderSpec.kt create mode 100644 store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/MemoryPolicyParametersSpec.kt create mode 100644 store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/StoreParametersSpec.kt create mode 100644 store/src/main/java/com/nytimes/android/external/store3/annotations/Experimental.java diff --git a/README.md b/README.md index 76b6797..a9e54eb 100644 --- a/README.md +++ b/README.md @@ -293,6 +293,11 @@ public class SampleStore extends RealStore { ```groovy compile 'com.nytimes.android:store3:CurrentVersion' ``` ++ **Store-Kotlin** Store plus a couple of added Kotlin classes for more idiomatic usage. + + ```groovy + compile 'com.nytimes.android:store-kotlin3:CurrentVersion' + ``` + **Middleware** Sample Gson parsers, (feel free to create more and open PRs) ```groovy diff --git a/build.gradle b/build.gradle index d5efac6..d9cdc0d 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,10 @@ buildscript { jcenter() } + rootProject.ext.versions = [ + kotlin: '1.1.2-5' + ] + dependencies { classpath 'com.android.tools.build:gradle:2.3.2' classpath 'com.google.gms:google-services:3.0.0' @@ -22,6 +26,8 @@ buildscript { classpath 'me.tatarka:gradle-retrolambda:3.6.1' classpath 'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2' classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.8' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.ext.versions.kotlin" + classpath 'org.jetbrains.dokka:dokka-gradle-plugin:0.9.14' } // this corresponds to the lombok.ast included above. fixes lint for retro-lambda diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 8d5349c..c24b8cd 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -12,7 +12,7 @@ allprojects { } } -ext.versions = [ +ext.versions += [ minSdk : 16, targetSdk : 25, compileSdk : 25, @@ -52,6 +52,7 @@ ext.versions = [ autoCommon : '0.6', javaWriter : '2.5.1', javax : '1', + commonsLang3 : '3.0', // Debugging & Inspecting. slf4j : '1.7.19', @@ -116,6 +117,8 @@ ext.libraries = [ autoCommon : "com.google.auto:auto-common:$versions.autoCommon", javaWriter : "com.squareup:javawriter:$versions.javaWriter", javax : "javax.inject:javax.inject:$versions.javax", + kotlinStdLib : "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin", + commonsLang3 : "org.apache.commons:commons-lang3:$versions.commonsLang3", // Debugging & Inspecting. slf4jNoOp : "org.slf4j:slf4j-api:$versions.slf4j", diff --git a/gradle/maven-push.gradle b/gradle/maven-push.gradle index d79b404..47ed256 100644 --- a/gradle/maven-push.gradle +++ b/gradle/maven-push.gradle @@ -47,7 +47,6 @@ afterEvaluate { project -> repositories { mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - pom.groupId = GROUP pom.artifactId = POM_ARTIFACT_ID pom.version = VERSION_NAME @@ -195,6 +194,11 @@ afterEvaluate { project -> classifier = 'javadoc' from javadoc.destinationDir } + + task kotlinJavadocJar(type: Jar, dependsOn:javadoc) { + classifier = 'javadoc' + from "$buildDir/dokka" + } } if (JavaVersion.current().isJava8Compatible()) { @@ -212,7 +216,11 @@ afterEvaluate { project -> archives androidJavadocsJar } else { archives sourcesJar - archives javadocJar + if (project.getPlugins().hasPlugin('kotlin')) { + archives kotlinJavadocJar + } else { + archives javadocJar + } } } -} \ No newline at end of file +} diff --git a/middleware-jackson/src/main/java/com/nytimes/android/external/store3/middleware/jackson/JacksonTransformerFactory.java b/middleware-jackson/src/main/java/com/nytimes/android/external/store3/middleware/jackson/JacksonTransformerFactory.java index 10ec686..ead0228 100644 --- a/middleware-jackson/src/main/java/com/nytimes/android/external/store3/middleware/jackson/JacksonTransformerFactory.java +++ b/middleware-jackson/src/main/java/com/nytimes/android/external/store3/middleware/jackson/JacksonTransformerFactory.java @@ -2,11 +2,10 @@ package com.nytimes.android.external.store3.middleware.jackson; import com.fasterxml.jackson.databind.ObjectMapper; import com.nytimes.android.external.fs3.ObjectToSourceTransformer; +import com.nytimes.android.external.store3.annotations.Experimental; import javax.annotation.Nonnull; -import io.reactivex.annotations.Experimental; - /** * Factory which returns Jackson {@link io.reactivex.SingleTransformer} implementations. */ diff --git a/middleware-moshi/src/main/java/com/nytimes/android/external/store3/middleware/moshi/MoshiTransformerFactory.java b/middleware-moshi/src/main/java/com/nytimes/android/external/store3/middleware/moshi/MoshiTransformerFactory.java index f9cfc88..d43b348 100644 --- a/middleware-moshi/src/main/java/com/nytimes/android/external/store3/middleware/moshi/MoshiTransformerFactory.java +++ b/middleware-moshi/src/main/java/com/nytimes/android/external/store3/middleware/moshi/MoshiTransformerFactory.java @@ -1,14 +1,13 @@ package com.nytimes.android.external.store3.middleware.moshi; import com.nytimes.android.external.fs3.ObjectToSourceTransformer; +import com.nytimes.android.external.store3.annotations.Experimental; import com.squareup.moshi.Moshi; import java.lang.reflect.Type; import javax.annotation.Nonnull; -import io.reactivex.annotations.Experimental; - /** * Factory which returns Moshi {@link io.reactivex.SingleTransformer} implementations. */ diff --git a/middleware/src/main/java/com/nytimes/android/external/store3/middleware/GsonTransformerFactory.java b/middleware/src/main/java/com/nytimes/android/external/store3/middleware/GsonTransformerFactory.java index 17a766f..c545f84 100644 --- a/middleware/src/main/java/com/nytimes/android/external/store3/middleware/GsonTransformerFactory.java +++ b/middleware/src/main/java/com/nytimes/android/external/store3/middleware/GsonTransformerFactory.java @@ -2,11 +2,10 @@ package com.nytimes.android.external.store3.middleware; import com.google.gson.Gson; import com.nytimes.android.external.fs3.ObjectToSourceTransformer; +import com.nytimes.android.external.store3.annotations.Experimental; import javax.annotation.Nonnull; -import io.reactivex.annotations.Experimental; - /** * Factory which returns Gson {@link io.reactivex.SingleTransformer} implementations. */ diff --git a/settings.gradle b/settings.gradle index 46953f8..b396eae 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':store', ':middleware', ':cache', ':filesystem', ':middleware-moshi', ':middleware-jackson' +include ':app', ':store', ':store-kotlin', ':middleware', ':cache', ':filesystem', ':middleware-moshi', ':middleware-jackson' diff --git a/store-kotlin/README.md b/store-kotlin/README.md new file mode 100644 index 0000000..5c4c901 --- /dev/null +++ b/store-kotlin/README.md @@ -0,0 +1,40 @@ +# store-kotlin + +Store with bindings for Kotlin. + +## Usage + +StoreBuilder: + +```kotlin +FluentStoreBuilder.barcode(myFetcher) { + persister = myPersister + memoryPolicy = myMemoryPolicy + stalePolicy = myStalePolicy +} +FluentStoreBuilder.key().fetcher(myFetcher) { + persister = myPersister + memoryPolicy = myMemoryPolicy + stalePolicy = myStalePolicy +} +FluentStoreBuilder.parsedWithKey(myFetcher) { + persister = myPersister + memoryPolicy = myMemoryPolicy + stalePolicy = myStalePolicy + parser = myParser + parsers = myParsers +} +``` + +MemoryPolicyBuilder: + +```kotlin +FluentMemoryPolicyBuilder.build { + expireAfterWrite = expireAfterWriteValue + expireAfterAccess = expireAfterWriteAccess + expireAfterTimeUnit = expireAfterTimeUnitValue + memorySize = maxSizeValue +} +``` + +And you can always omit the configuration block if you're happy with the defaults! diff --git a/store-kotlin/build.gradle b/store-kotlin/build.gradle new file mode 100644 index 0000000..8dbd77a --- /dev/null +++ b/store-kotlin/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'java' +apply plugin: 'kotlin' +apply plugin: 'org.jetbrains.dokka' + +group = GROUP +version = VERSION_NAME + +compileKotlin { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + kotlinOptions.jvmTarget = "1.8" +} + +javadoc.dependsOn dokka + +dependencies { + compile project(':store') + compile libraries.kotlinStdLib + + testCompile libraries.mockito + testCompile libraries.junit + testCompile libraries.commonsLang3 + testCompile libraries.assertJ +} + +apply from: rootProject.file("gradle/maven-push.gradle") diff --git a/store-kotlin/gradle.properties b/store-kotlin/gradle.properties new file mode 100644 index 0000000..10faffc --- /dev/null +++ b/store-kotlin/gradle.properties @@ -0,0 +1,3 @@ +POM_NAME=com.nytimes.android +POM_ARTIFACT_ID=store-kotlin3 +POM_PACKAGING=aar diff --git a/store-kotlin/src/main/AndroidManifest.xml b/store-kotlin/src/main/AndroidManifest.xml new file mode 100644 index 0000000..0b68540 --- /dev/null +++ b/store-kotlin/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentMemoryPolicyBuilder.kt b/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentMemoryPolicyBuilder.kt new file mode 100644 index 0000000..a5b69c1 --- /dev/null +++ b/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentMemoryPolicyBuilder.kt @@ -0,0 +1,31 @@ +package com.nytimes.android.external.store3.base.impl + +import com.nytimes.android.external.store3.annotations.Experimental + +/** + * Wraps methods for fluent MemoryPolicy instantiation. + */ +@Experimental +class FluentMemoryPolicyBuilder private constructor() { + companion object { + /** + * Builds a MemoryPolicy. + * @param config The desired configuration for the memory policy. + * @return A MemoryPolicy with the desired parameters or default ones if none were provided. + */ + fun build(config: (MemoryPolicyParameters.() -> Unit)? = null): MemoryPolicy = + MemoryPolicyParameters().apply { config?.invoke(this) }.let { + MemoryPolicy.builder() + .apply { + if (it.expireAfterAccess != MemoryPolicy.DEFAULT_POLICY) { + this.setExpireAfterAccess(it.expireAfterAccess) + } else if (it.expireAfterWrite != MemoryPolicy.DEFAULT_POLICY) { + this.setExpireAfterWrite(it.expireAfterWrite) + } + } + .setExpireAfterTimeUnit(it.expireAfterTimeUnit) + .setMemorySize(it.memorySize) + .build() + } + } +} diff --git a/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentRealStoreBuilder.kt b/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentRealStoreBuilder.kt new file mode 100644 index 0000000..2cfb538 --- /dev/null +++ b/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentRealStoreBuilder.kt @@ -0,0 +1,46 @@ +package com.nytimes.android.external.store3.base.impl + +import com.nytimes.android.external.store3.base.Fetcher +import com.nytimes.android.external.store3.base.Parser +import com.nytimes.android.external.store3.base.Persister +import com.nytimes.android.external.store3.util.KeyParser + +/** + * A fluent builder for Store instantiation. + * @param fetcher The fetcher for the created instance. + */ +internal class FluentRealStoreBuilder constructor( + private val fetcher: Fetcher, + private val persister: Persister?, + private val keyParser: KeyParser?, + private val parsers: List>?, + private val memoryPolicy: MemoryPolicy?, + private val stalePolicy: StalePolicy) { + /** + * Creates the Store instance. + * @return The created Store with the parameters passed into the constructor. + */ + fun open(): Store { + var builder = StoreBuilder.parsedWithKey() + .fetcher(fetcher) + if (persister != null) { + builder = builder.persister(persister) + } + if (keyParser != null) { + builder = builder.parser(keyParser) + } else { + if (parsers != null) { + builder = builder.parsers(parsers) + } + } + if (memoryPolicy != null) { + builder = builder.memoryPolicy(memoryPolicy) + } + when (stalePolicy) { + StalePolicy.REFRESH_ON_STALE -> builder = builder.refreshOnStale() + StalePolicy.NETWORK_BEFORE_STALE -> builder = builder.networkBeforeStale() + StalePolicy.UNSPECIFIED -> { } // Do nothing + } + return builder.open() + } +} diff --git a/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentStoreBuilder.kt b/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentStoreBuilder.kt new file mode 100644 index 0000000..ccaae34 --- /dev/null +++ b/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/FluentStoreBuilder.kt @@ -0,0 +1,60 @@ +package com.nytimes.android.external.store3.base.impl + +import com.nytimes.android.external.store3.annotations.Experimental +import com.nytimes.android.external.store3.base.Fetcher + +/** + * Wraps methods for fluent Store instantiation. + */ +@Experimental +class FluentStoreBuilder private constructor() { + companion object { + /** + * Provides a fluent builder to instantiate a Store that uses BarCode objects as keys. + * @param fetcher Fetcher for the Store. + * @param config Optional configuration block. + */ + fun barcode( + fetcher: Fetcher, + config: (StoreParameters.() -> Unit)? = null) = + key(fetcher, config) + + /** + * Provides a fluent builder to instantiate a Store with a custom type for keys. + * @param fetcher Fetcher for the Store. + * @param config Optional configuration block. + */ + fun key( + fetcher: Fetcher, + config: (StoreParameters.() -> Unit)? = null) = + StoreParameters(fetcher).apply { + if (config != null) { + this.config() + } + }.let { + FluentRealStoreBuilder( + fetcher, it.persister, null, null, it.memoryPolicy, it.stalePolicy) + .open() + } + + /** + * Provides a fluent builder to instantiate a Store with a custom type for keys and + * conversion between raw and parsed types. + * @param fetcher Fetcher for the Store. + * @param config Optional configuration block. + */ + fun parsedWithKey( + fetcher: Fetcher, + config: (ParsableStoreParameters.() -> Unit)? = null) = + ParsableStoreParameters(fetcher).apply { + if (config != null) { + this.config() + } + }.let { + FluentRealStoreBuilder( + fetcher, it.persister, it.parser, it.parsers, it.memoryPolicy, + it.stalePolicy) + .open() + } + } +} diff --git a/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/MemoryPolicyParameters.kt b/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/MemoryPolicyParameters.kt new file mode 100644 index 0000000..432265f --- /dev/null +++ b/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/MemoryPolicyParameters.kt @@ -0,0 +1,22 @@ +package com.nytimes.android.external.store3.base.impl + +import com.nytimes.android.external.store3.annotations.Experimental +import java.util.concurrent.TimeUnit +import kotlin.properties.Delegates + +/** + * A parameter box for MemoryPolicy instantiation. + */ +@Experimental +class MemoryPolicyParameters { + var expireAfterWrite by Delegates.vetoable(MemoryPolicy.DEFAULT_POLICY) { + _, _, newValue -> newValue >= 0 + } + var expireAfterAccess by Delegates.vetoable(MemoryPolicy.DEFAULT_POLICY) { + _, _, newValue -> newValue >= 0 + } + var expireAfterTimeUnit = TimeUnit.SECONDS + var memorySize by Delegates.vetoable(1L) { + _, _, newValue -> newValue >= 1 + } +} diff --git a/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/StoreParameters.kt b/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/StoreParameters.kt new file mode 100644 index 0000000..d171408 --- /dev/null +++ b/store-kotlin/src/main/kotlin/com/nytimes/android/external/store3/base/impl/StoreParameters.kt @@ -0,0 +1,41 @@ +package com.nytimes.android.external.store3.base.impl + +import com.nytimes.android.external.store3.annotations.Experimental +import com.nytimes.android.external.store3.base.Fetcher +import com.nytimes.android.external.store3.base.Parser +import com.nytimes.android.external.store3.base.Persister +import com.nytimes.android.external.store3.util.KeyParser + +/** + * A parameter box for Store instantiation, used for Stores the do not make use of parsing. + * @param fetcher The fetcher for the Store. + */ +@Experimental +open class StoreParameters internal constructor(private val fetcher: Fetcher) { + var persister: Persister? = null + var memoryPolicy: MemoryPolicy? = null + var stalePolicy: StalePolicy = StalePolicy.UNSPECIFIED +} + +/** + * A parameter box for Store instantiation, used for Stores that can have parsing. + * @param fetcher The fetcher for the Store. + */ +@Experimental +class ParsableStoreParameters internal constructor(fetcher: Fetcher) + : StoreParameters(fetcher) { + var parser: KeyParser? = null + set(value) { + field = value + if (value != null) { + parsers = null + } + } + var parsers: List>? = null + set(value) { + field = value + if (value != null) { + parser = null + } + } +} diff --git a/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentMemoryPolicyBuilderSpec.kt b/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentMemoryPolicyBuilderSpec.kt new file mode 100644 index 0000000..fe68d81 --- /dev/null +++ b/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentMemoryPolicyBuilderSpec.kt @@ -0,0 +1,50 @@ +package com.nytimes.android.external.store3.base.impl + +import org.apache.commons.lang3.builder.EqualsBuilder +import org.junit.Test +import java.util.concurrent.TimeUnit + +/** + * Spec for FluentMemoryPolicyBuilder. + */ +class FluentMemoryPolicyBuilderSpec { + @Test + fun shouldBuildAnEquivalentObjectWithAfterWrite() { + val expireAfterWriteValue = 10L + val expireAfterTimeUnitValue = TimeUnit.MILLISECONDS + val maxSizeValue = 1000L + val javaResult = MemoryPolicy.builder() + .setExpireAfterWrite(expireAfterWriteValue) + .setExpireAfterTimeUnit(expireAfterTimeUnitValue) + .setMemorySize(maxSizeValue) + .build() + val kotlinResult = FluentMemoryPolicyBuilder.build { + expireAfterWrite = expireAfterWriteValue + expireAfterTimeUnit = expireAfterTimeUnitValue + memorySize = maxSizeValue + } + assertEquivalent(javaResult, kotlinResult) + } + + @Test + fun shouldBuildAnEquivalentObjectWithAfterAccess() { + val expireAfterAccessValue = 20L + val expireAfterTimeUnitValue = TimeUnit.MILLISECONDS + val maxSizeValue = 1000L + val javaResult = MemoryPolicy.builder() + .setExpireAfterAccess(expireAfterAccessValue) + .setExpireAfterTimeUnit(expireAfterTimeUnitValue) + .setMemorySize(maxSizeValue) + .build() + val kotlinResult = FluentMemoryPolicyBuilder.build { + expireAfterAccess = expireAfterAccessValue + expireAfterTimeUnit = expireAfterTimeUnitValue + memorySize = maxSizeValue + } + assertEquivalent(javaResult, kotlinResult) + } + + private fun assertEquivalent(expected: MemoryPolicy, actual: MemoryPolicy) = + EqualsBuilder.reflectionEquals(expected, actual) +} + diff --git a/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentRealStoreBuilderSpec.kt b/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentRealStoreBuilderSpec.kt new file mode 100644 index 0000000..9b65471 --- /dev/null +++ b/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentRealStoreBuilderSpec.kt @@ -0,0 +1,43 @@ +package com.nytimes.android.external.store3.base.impl + +import com.nytimes.android.external.store3.base.Fetcher +import com.nytimes.android.external.store3.base.Parser +import com.nytimes.android.external.store3.base.Persister +import com.nytimes.android.external.store3.util.KeyParser +import org.apache.commons.lang3.builder.EqualsBuilder +import org.junit.Test +import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock +import java.util.concurrent.TimeUnit + +/** + * Spec for FluentRealStoreBuilder. + */ +@Suppress("UNCHECKED_CAST") +class FluentRealStoreBuilderSpec { + @Test + fun shouldOpenAnEquivalentObject() { + val fetcher = mock(Fetcher::class.java) as Fetcher + val persister = mock(Persister::class.java) as Persister + val keyParser = mock(KeyParser::class.java) as KeyParser + val parsers = listOf>() + val memoryPolicy = mock(MemoryPolicy::class.java) + `when`(memoryPolicy.expireAfterTimeUnit).thenReturn(TimeUnit.MILLISECONDS) + val stalePolicy = StalePolicy.NETWORK_BEFORE_STALE + val javaResult = RealStoreBuilder.builder() + .fetcher(fetcher) + .persister(persister) + .parser(keyParser) + .parsers(parsers) + .memoryPolicy(memoryPolicy) + .networkBeforeStale() + .open() + val kotlinResult = FluentRealStoreBuilder(fetcher, persister, keyParser, parsers, + memoryPolicy, stalePolicy + ).open() + assertEquivalent(javaResult, kotlinResult) + } + + private fun assertEquivalent(expected: Store, actual: Store) = + EqualsBuilder.reflectionEquals(expected, actual) +} diff --git a/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentStoreBuilderSpec.kt b/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentStoreBuilderSpec.kt new file mode 100644 index 0000000..cf7c044 --- /dev/null +++ b/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/FluentStoreBuilderSpec.kt @@ -0,0 +1,47 @@ +package com.nytimes.android.external.store3.base.impl + +import com.nytimes.android.external.store3.base.Fetcher +import org.apache.commons.lang3.builder.EqualsBuilder +import org.junit.Test +import org.mockito.Mockito + +/** + * Spec for FluentStoreBuilder. + */ +class FluentStoreBuilderSpec { + @Test + fun equivalentBarcode() { + @Suppress("UNCHECKED_CAST") + val fetcher = Mockito.mock(Fetcher::class.java) as Fetcher + val javaResult = StoreBuilder.barcode() + .fetcher(fetcher) + .open() + val kotlinResult = FluentStoreBuilder.barcode(fetcher) + assertEquivalent(javaResult, kotlinResult) + } + + @Test + fun equivalentKey() { + @Suppress("UNCHECKED_CAST") + val fetcher = Mockito.mock(Fetcher::class.java) as Fetcher + val javaResult = StoreBuilder.key() + .fetcher(fetcher) + .open() + val kotlinResult = FluentStoreBuilder.key(fetcher) + assertEquivalent(javaResult, kotlinResult) + } + + @Test + fun equivalentParsedWithKey() { + @Suppress("UNCHECKED_CAST") + val fetcher = Mockito.mock(Fetcher::class.java) as Fetcher + val javaResult = StoreBuilder.parsedWithKey() + .fetcher(fetcher) + .open() + val kotlinResult = FluentStoreBuilder.parsedWithKey(fetcher) + assertEquivalent(javaResult, kotlinResult) + } + + private fun assertEquivalent(expected: Store, actual: Store) = + EqualsBuilder.reflectionEquals(expected, actual) +} diff --git a/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/MemoryPolicyParametersSpec.kt b/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/MemoryPolicyParametersSpec.kt new file mode 100644 index 0000000..aefca0f --- /dev/null +++ b/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/MemoryPolicyParametersSpec.kt @@ -0,0 +1,67 @@ +package com.nytimes.android.external.store3.base.impl + +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import java.util.concurrent.TimeUnit + +/** + * Spec for MemoryPolicyParameters. + */ +class MemoryPolicyParametersSpec { + @Test + fun shouldHaveExpireAfterWriteBeMemoryPolicyDEFAULT_POLICY() { + val sut = MemoryPolicyParameters() + assertThat(sut.expireAfterWrite).isEqualTo(MemoryPolicy.DEFAULT_POLICY) + } + + @Test + fun shouldHaveExpireAfterAccessBeMemoryPolicyDEFAULT_POLICY() { + val sut = MemoryPolicyParameters() + assertThat(sut.expireAfterAccess).isEqualTo(MemoryPolicy.DEFAULT_POLICY) + } + + @Test + fun shouldHaveExpireAfterTimeUnitBeTimeUnitSECONDS() { + val sut = MemoryPolicyParameters() + assertThat(sut.expireAfterTimeUnit).isEqualTo(TimeUnit.SECONDS) + } + + @Test + fun shouldHaveMemorySizeBe1() { + val sut = MemoryPolicyParameters() + assertThat(sut.memorySize).isEqualTo(1) + } + + @Test + fun expiredAfterWriteMustBeGreaterThanOrEqualTo0() { + val sut = MemoryPolicyParameters() + val validValue = 82L + val invalidValue = -1L + sut.expireAfterWrite = validValue + assertThat(sut.expireAfterWrite).isEqualTo(validValue) + sut.expireAfterWrite = invalidValue + assertThat(sut.expireAfterWrite).isEqualTo(validValue) + } + + @Test + fun expiredAfterAccessMustBeGreaterThanOrEqualTo0() { + val sut = MemoryPolicyParameters() + val validValue = 82L + val invalidValue = -1L + sut.expireAfterAccess = validValue + assertThat(sut.expireAfterAccess).isEqualTo(validValue) + sut.expireAfterAccess = invalidValue + assertThat(sut.expireAfterAccess).isEqualTo(validValue) + } + + @Test + fun memorySizeShouldBeGreaterThanOrEqualTo1() { + val sut = MemoryPolicyParameters() + val validValue = 3L + val invalidValue = -1L + sut.memorySize = validValue + assertThat(sut.memorySize).isEqualTo(validValue) + sut.memorySize = invalidValue + assertThat(sut.memorySize).isEqualTo(validValue) + } +} diff --git a/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/StoreParametersSpec.kt b/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/StoreParametersSpec.kt new file mode 100644 index 0000000..e0378b9 --- /dev/null +++ b/store-kotlin/src/test/kotlin/com/nytimes/android/external/store3/base/impl/StoreParametersSpec.kt @@ -0,0 +1,66 @@ +package com.nytimes.android.external.store3.base.impl + +import com.nytimes.android.external.store3.base.Fetcher +import com.nytimes.android.external.store3.base.Parser +import com.nytimes.android.external.store3.util.KeyParser +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import org.mockito.Mockito.mock + +/** + * Spec for StoreParameters. + */ +open class StoreParametersSpec { + @Test + fun defaultPersisterIsNull() { + @Suppress("UNCHECKED_CAST") + val sut = StoreParameters(mock(Fetcher::class.java) as Fetcher) + assertThat(sut.persister).isNull() + } + @Test + fun defaultMemoryPolicyIsNull() { + @Suppress("UNCHECKED_CAST") + val sut = StoreParameters(mock(Fetcher::class.java) as Fetcher) + assertThat(sut.memoryPolicy).isNull() + } + @Test + fun defaultStalePolicyIsUnspecified() { + @Suppress("UNCHECKED_CAST") + val sut = StoreParameters(mock(Fetcher::class.java) as Fetcher) + assertThat(sut.stalePolicy).isEqualTo(StalePolicy.UNSPECIFIED) + } +} + +/** + * Spec for ParsableStoreParameters. + */ +@Suppress("UNCHECKED_CAST") +class ParsableStoreParametersSpec : StoreParametersSpec() { + @Test + fun defaultParserIsNull() { + val sut = ParsableStoreParameters(mock(Fetcher::class.java) as Fetcher) + assertThat(sut.parser).isNull() + } + + @Test + fun defaultParsersIsNull() { + val sut = ParsableStoreParameters(mock(Fetcher::class.java) as Fetcher) + assertThat(sut.parsers).isNull() + } + + @Test + fun shouldMakeParserNullWhenParsersIsAssigned() { + val sut = ParsableStoreParameters(mock(Fetcher::class.java) as Fetcher) + sut.parser = mock(KeyParser::class.java) as KeyParser + sut.parsers = mock(List::class.java) as List> + assertThat(sut.parser).isNull() + } + + @Test + fun shouldMakeParsersNullWhenParserIsAssigned() { + val sut = ParsableStoreParameters(mock(Fetcher::class.java) as Fetcher) + sut.parsers = mock(List::class.java) as List> + sut.parser = mock(KeyParser::class.java) as KeyParser + assertThat(sut.parsers).isNull() + } +} diff --git a/store/src/main/java/com/nytimes/android/external/store3/annotations/Experimental.java b/store/src/main/java/com/nytimes/android/external/store3/annotations/Experimental.java new file mode 100644 index 0000000..cf46747 --- /dev/null +++ b/store/src/main/java/com/nytimes/android/external/store3/annotations/Experimental.java @@ -0,0 +1,8 @@ +package com.nytimes.android.external.store3.annotations; + +/** + * Indicates the feature is in experimental state: its existence, signature or behavior + * might change without warning from one release to the next. + */ +public @interface Experimental { +} diff --git a/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealInternalStore.java b/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealInternalStore.java index ed111ee..25dc012 100644 --- a/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealInternalStore.java +++ b/store/src/main/java/com/nytimes/android/external/store3/base/impl/RealInternalStore.java @@ -1,6 +1,7 @@ package com.nytimes.android.external.store3.base.impl; import com.nytimes.android.external.cache3.Cache; +import com.nytimes.android.external.store3.annotations.Experimental; import com.nytimes.android.external.store3.base.Fetcher; import com.nytimes.android.external.store3.base.InternalStore; import com.nytimes.android.external.store3.base.Persister; @@ -15,7 +16,6 @@ import javax.annotation.Nullable; import io.reactivex.Maybe; import io.reactivex.Observable; import io.reactivex.Single; -import io.reactivex.annotations.Experimental; import io.reactivex.subjects.PublishSubject; /** diff --git a/store/src/main/java/com/nytimes/android/external/store3/base/impl/Store.java b/store/src/main/java/com/nytimes/android/external/store3/base/impl/Store.java index c613e38..3082859 100644 --- a/store/src/main/java/com/nytimes/android/external/store3/base/impl/Store.java +++ b/store/src/main/java/com/nytimes/android/external/store3/base/impl/Store.java @@ -1,11 +1,12 @@ package com.nytimes.android.external.store3.base.impl; +import com.nytimes.android.external.store3.annotations.Experimental; + import javax.annotation.Nonnull; import io.reactivex.Observable; import io.reactivex.Single; -import io.reactivex.annotations.Experimental; /**