diff --git a/.github/workflows/publish_snapshot.yml b/.github/workflows/publish_snapshot.yml index ae86752..b178b5c 100644 --- a/.github/workflows/publish_snapshot.yml +++ b/.github/workflows/publish_snapshot.yml @@ -2,7 +2,7 @@ name: Publish snapshot on: push: - branches: [ master, feature/* ] + branches: [ master, feature/*, kotlin-* ] pull_request: branches: [ master ] diff --git a/.github/workflows/test.yml b/.github/workflows/pull_request.yml similarity index 67% rename from .github/workflows/test.yml rename to .github/workflows/pull_request.yml index 96b23f1..c076f19 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/pull_request.yml @@ -1,4 +1,4 @@ -name: Test +name: PR on: pull_request: @@ -7,13 +7,25 @@ on: - '*.md' jobs: - test: + ktlint: runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Ktlint + uses: "vroy/gha-kotlin-linter@v1" + test: + needs: ktlint + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest, windows-latest, ubuntu-latest] steps: - uses: actions/checkout@v2 - name: Test - run: ./gradlew jvmTest + run: ./gradlew allTest - name: Archive redux-kotlin Test Reports uses: actions/upload-artifact@v1 diff --git a/build.gradle b/build.gradle deleted file mode 100644 index f1e6693..0000000 --- a/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -buildscript { - repositories { - google() - maven { url 'https://dl.bintray.com/jetbrains/kotlin-native-dependencies' } - maven { url "https://plugins.gradle.org/m2/" } - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - jcenter() - } - - dependencies { - classpath Plugins.kotlin - classpath Plugins.dokka - classpath Plugins.android - classpath Plugins.atomicFu - } -} - -plugins { - id("de.fayard.buildSrcVersions") version "0.4.2" -} - -allprojects { - repositories { - google() - jcenter() - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - maven { url "https://dl.bintray.com/spekframework/spek-dev" } - mavenCentral() - } - - group = GROUP - version = VERSION_NAME - if (hasProperty("SNAPSHOT") || System.getenv("SNAPSHOT") != null) { - version = version + "-SNAPSHOT" - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} - diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..77907c5 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,38 @@ + +buildscript { + repositories { + google() + mavenCentral() + maven("https://dl.bintray.com/jetbrains/kotlin-native-dependencies") + maven("https://plugins.gradle.org/m2/") + maven("https://oss.sonatype.org/content/repositories/snapshots") + jcenter() + } + + dependencies { + classpath(Plugins.kotlin) + classpath(Plugins.dokka) + classpath(Plugins.android) + classpath(Plugins.atomicFu) + } +} + +plugins { + id("de.fayard.buildSrcVersions") version "0.4.2" +} + +allprojects { + repositories { + google() + jcenter() + maven("https://kotlin.bintray.com/kotlinx") + maven("https://oss.sonatype.org/content/repositories/snapshots") + mavenCentral() + } + + group = project.properties["GROUP"]!! + version = project.properties["VERSION_NAME"]!! + if (hasProperty("SNAPSHOT") || System.getenv("SNAPSHOT") != null) { + version = "$version-SNAPSHOT" + } +} diff --git a/buildSrc/src/main/kotlin/Libs.kt b/buildSrc/src/main/kotlin/Libs.kt index 14bdb1a..6cf8563 100644 --- a/buildSrc/src/main/kotlin/Libs.kt +++ b/buildSrc/src/main/kotlin/Libs.kt @@ -7,186 +7,178 @@ import kotlin.String * `$ ./gradlew buildSrcVersions` */ object Libs { - /** - * http://developer.android.com/tools/extras/support-library.html - */ - const val appcompat: String = "androidx.appcompat:appcompat:" + Versions.appcompat - - /** - * https://developer.android.com/reference/android/support/constraint/ConstraintLayout - */ - const val constraintLayout = "androidx.constraintlayout:constraintlayout:" + Versions.constraint_layout - - /** - * https://developer.android.com/guide/topics/ui/layout/recyclerview - */ - const val recyclerView = "androidx.recyclerview:recyclerview:" + Versions.recycler_view - - /** - * https://developer.android.com/testing - */ - const val espresso_core: String = "androidx.test.espresso:espresso-core:" + Versions.espresso_core - - /** - * https://developer.android.com/testing - */ - const val androidx_test_runner: String = "androidx.test:runner:" + Versions.androidx_test_runner - - /** - * https://github.com/robstoll/atrium - */ - const val atrium_cc_en_gb_robstoll_common: String = - "ch.tutteli.atrium:atrium-cc-en_GB-robstoll-common:" + Versions.atrium - - /** - * https://github.com/robstoll/atrium - */ - const val atrium_cc_en_gb_robstoll: String = "ch.tutteli.atrium:atrium-cc-en_GB-robstoll:" + - Versions.atrium - - /** - * https://developer.android.com/studio - */ - const val aapt2: String = "com.android.tools.build:aapt2:" + Versions.aapt2 - - /** - * https://developer.android.com/studio - */ - const val com_android_tools_build_gradle: String = "com.android.tools.build:gradle:" + - Versions.com_android_tools_build_gradle - - /** - * https://developer.android.com/studio - */ - const val lint_gradle: String = "com.android.tools.lint:lint-gradle:" + Versions.lint_gradle - - const val de_fayard_buildsrcversions_gradle_plugin: String = - "de.fayard.buildSrcVersions:de.fayard.buildSrcVersions.gradle.plugin:" + - Versions.de_fayard_buildsrcversions_gradle_plugin - - /** - * http://mockk.io - */ - const val mockk_common: String = "io.mockk:mockk-common:" + Versions.mockk - - /** - * http://mockk.io - */ - const val mockk: String = "io.mockk:mockk:" + Versions.mockk - - /** - * http://junit.org - */ - const val junit: String = "junit:junit:" + Versions.junit - - const val dokka_gradle_plugin: String = "org.jetbrains.dokka:dokka-gradle-plugin:" + - Versions.dokka_gradle_plugin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_android_extensions_runtime: String = - "org.jetbrains.kotlin:kotlin-android-extensions-runtime:" + Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_android_extensions: String = "org.jetbrains.kotlin:kotlin-android-extensions:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_annotation_processing_gradle: String = - "org.jetbrains.kotlin:kotlin-annotation-processing-gradle:" + Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_gradle_plugin: String = "org.jetbrains.kotlin:kotlin-gradle-plugin:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_reflect: String = "org.jetbrains.kotlin:kotlin-reflect:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_scripting_compiler_embeddable: String = - "org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:" + Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_stdlib_common: String = "org.jetbrains.kotlin:kotlin-stdlib-common:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_stdlib_jdk8: String = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_stdlib_js: String = "org.jetbrains.kotlin:kotlin-stdlib-js:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_stdlib: String = "org.jetbrains.kotlin:kotlin-stdlib:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_test_annotations_common: String = - "org.jetbrains.kotlin:kotlin-test-annotations-common:" + Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_test_common: String = "org.jetbrains.kotlin:kotlin-test-common:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_test_js: String = "org.jetbrains.kotlin:kotlin-test-js:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_test_junit: String = "org.jetbrains.kotlin:kotlin-test-junit:" + - Versions.org_jetbrains_kotlin - - /** - * https://kotlinlang.org/ - */ - const val kotlin_test: String = "org.jetbrains.kotlin:kotlin-test:" + - Versions.org_jetbrains_kotlin - - const val spek_dsl_jvm: String = "org.spekframework.spek2:spek-dsl-jvm:" + - Versions.spek - - const val spek_dsl_metadata: String = "org.spekframework.spek2:spek-dsl-metadata:" + - Versions.spek - - const val spek_runner_junit5: String = "org.spekframework.spek2:spek-runner-junit5:" + - Versions.spek - - const val kotlin_coroutines: String = "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:" + - Versions.coroutines - - const val kotlin_coroutines_jvm: String = "org.jetbrains.kotlinx:kotlinx-coroutines-core:" + - Versions.coroutines - - const val kotlin_coroutines_test: String = "org.jetbrains.kotlinx:kotlinx-coroutines-test:" + - Versions.coroutines + /** + * https://developer.android.com/jetpack/androidx + */ + const val appcompat: String = "androidx.appcompat:appcompat:" + Versions.appcompat + + /** + * http://tools.android.com + */ + const val constraintlayout: String = "androidx.constraintlayout:constraintlayout:" + + Versions.constraintlayout + + /** + * https://developer.android.com/jetpack/androidx + */ + const val recyclerview: String = "androidx.recyclerview:recyclerview:" + Versions.recyclerview + + /** + * https://developer.android.com/studio + */ + const val aapt2: String = "com.android.tools.build:aapt2:" + Versions.aapt2 + + /** + * https://developer.android.com/studio + */ + const val com_android_tools_build_gradle: String = "com.android.tools.build:gradle:" + + Versions.com_android_tools_build_gradle + + /** + * https://developer.android.com/studio + */ + const val lint_gradle: String = "com.android.tools.lint:lint-gradle:" + Versions.lint_gradle + + const val de_fayard_buildsrcversions_gradle_plugin: String = + "de.fayard.buildSrcVersions:de.fayard.buildSrcVersions.gradle.plugin:" + + Versions.de_fayard_buildsrcversions_gradle_plugin + + /** + * http://mockk.io + */ + const val mockk_common: String = "io.mockk:mockk-common:" + Versions.io_mockk + + /** + * http://mockk.io + */ + const val mockk: String = "io.mockk:mockk:" + Versions.io_mockk + + const val dokka_gradle_plugin: String = "org.jetbrains.dokka:dokka-gradle-plugin:" + + Versions.dokka_gradle_plugin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_android_extensions_runtime: String = + "org.jetbrains.kotlin:kotlin-android-extensions-runtime:" + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_android_extensions: String = + "org.jetbrains.kotlin:kotlin-android-extensions:" + + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_annotation_processing_gradle: String = + "org.jetbrains.kotlin:kotlin-annotation-processing-gradle:" + Versions.org_jetbrains_kotlin + + const val kotlin_compiler_embeddable: String = + "org.jetbrains.kotlin:kotlin-compiler-embeddable:" + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_gradle_plugin: String = "org.jetbrains.kotlin:kotlin-gradle-plugin:" + + Versions.org_jetbrains_kotlin + + const val kotlin_klib_commonizer_embeddable: String = + "org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:" + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_reflect: String = "org.jetbrains.kotlin:kotlin-reflect:" + + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_scripting_compiler_embeddable: String = + "org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:" + Versions.org_jetbrains_kotlin + + /** + * 1.3.72 + */ + const val kotlin_stdlib_common: String = "org.jetbrains.kotlin:kotlin-stdlib-common:" + + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_stdlib_jdk8: String = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:" + + Versions.org_jetbrains_kotlin + + /** + * 1.3.72 + */ + const val kotlin_stdlib_js: String = "org.jetbrains.kotlin:kotlin-stdlib-js:" + + Versions.org_jetbrains_kotlin + + /** + * 1.3.72 + */ + const val kotlin_stdlib: String = "org.jetbrains.kotlin:kotlin-stdlib:" + + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_test_annotations_common: String = + "org.jetbrains.kotlin:kotlin-test-annotations-common:" + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_test_common: String = "org.jetbrains.kotlin:kotlin-test-common:" + + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_test_js: String = "org.jetbrains.kotlin:kotlin-test-js:" + + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_test_junit: String = "org.jetbrains.kotlin:kotlin-test-junit:" + + Versions.org_jetbrains_kotlin + + /** + * https://kotlinlang.org/ + */ + const val kotlin_test: String = "org.jetbrains.kotlin:kotlin-test:" + + Versions.org_jetbrains_kotlin + + /** + * https://github.com/Kotlin/atomicfu + */ + const val atomicfu_gradle_plugin: String = "org.jetbrains.kotlinx:atomicfu-gradle-plugin:" + + Versions.atomicfu_gradle_plugin + + /** + * https://github.com/Kotlin/atomicfu + */ + const val atomicfu: String = "org.jetbrains.kotlinx:atomicfu:" + Versions.atomicfu + + /** + * https://github.com/Kotlin/kotlinx.coroutines + */ + const val kotlinx_coroutines_core_jvm: String = + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:" + Versions.kotlinx_coroutines_core_jvm + + /** + * https://github.com/Kotlin/kotlinx.coroutines + */ + const val kotlinx_coroutines_core: String = "org.jetbrains.kotlinx:kotlinx-coroutines-core:" + + Versions.kotlinx_coroutines_core + + /** + * https://github.com/Kotlin/kotlinx.coroutines + */ + const val kotlinx_coroutines_test: String = "org.jetbrains.kotlinx:kotlinx-coroutines-test:" + + Versions.kotlinx_coroutines_test } diff --git a/buildSrc/src/main/kotlin/Plugins.kt b/buildSrc/src/main/kotlin/Plugins.kt index c7fec7d..f718653 100644 --- a/buildSrc/src/main/kotlin/Plugins.kt +++ b/buildSrc/src/main/kotlin/Plugins.kt @@ -1,6 +1,6 @@ object Plugins { const val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.org_jetbrains_kotlin}" - const val dokka = "org.jetbrains.dokka:dokka-gradle-plugin:${Versions.dokka_gradle_plugin}" + const val dokka = "org.jetbrains.dokka:dokka-gradle-plugin:${Versions.dokka_gradle_plugin}" const val android = "com.android.tools.build:gradle:${Versions.com_android_tools_build_gradle}" - const val atomicFu = "org.jetbrains.kotlinx:atomicfu-gradle-plugin:${Versions.atomicFu}" + const val atomicFu = "org.jetbrains.kotlinx:atomicfu-gradle-plugin:${Versions.atomicfu}" } diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 1cfd377..18a7463 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,6 +1,6 @@ -import kotlin.String import org.gradle.plugin.use.PluginDependenciesSpec import org.gradle.plugin.use.PluginDependencySpec +import kotlin.String /** * Generated by https://github.com/jmfayard/buildSrcVersions @@ -12,49 +12,44 @@ import org.gradle.plugin.use.PluginDependencySpec * YOU are responsible for updating manually the dependency version. */ object Versions { - const val appcompat: String = "1.1.0-rc01" - - const val espresso_core: String = "3.2.0" - - const val androidx_test_runner: String = "1.2.0" + const val appcompat: String = "1.1.0-rc01" // available: "1.1.0" - const val atrium: String = "0.9.2" + const val constraintlayout: String = "1.1.3" - const val aapt2: String = "3.5.0-5435860" + const val recyclerview: String = "1.0.0" // available: "1.1.0" - const val com_android_tools_build_gradle: String = "3.6.0" + const val aapt2: String = "3.6.0-6040484" // available: "4.0.1-6197926" - const val lint_gradle: String = "26.5.0" + const val com_android_tools_build_gradle: String = "3.6.0" // available: "4.0.1" - const val de_fayard_buildsrcversions_gradle_plugin: String = "0.4.2" + const val lint_gradle: String = "26.6.0" // available: "27.0.1" - const val mockk: String = "1.9.3" + const val de_fayard_buildsrcversions_gradle_plugin: String = "0.4.2" // available: "0.7.0" - const val junit: String = "4.12" + const val io_mockk: String = "1.9.3" // available: "1.10.0" - const val dokka_gradle_plugin: String = "0.9.17" // available: "0.9.18" + const val dokka_gradle_plugin: String = "0.9.17" // available: "0.11.0-dev-59" - const val org_jetbrains_kotlin: String = "1.3.72" + const val org_jetbrains_kotlin: String = "1.4.0" - const val spek: String = "2.1.0-alpha.0.11+d97ef33" - // available: "2.1.0-alpha.0.24+0fdeb6e" + const val atomicfu_gradle_plugin: String = "0.14.3-1.4.0-rc" - const val constraint_layout = "1.1.3" + const val atomicfu: String = "0.14.3-1.4.0-rc" - const val recycler_view = "1.0.0" + const val kotlinx_coroutines_core_jvm: String = "1.3.8-1.4.0-rc" - const val coroutines = "1.3.7" + const val kotlinx_coroutines_core: String = "1.3.8-1.4.0-rc" - const val atomicFu = "0.14.2" + const val kotlinx_coroutines_test: String = "1.3.8-1.4.0-rc" - /** - * - * See issue 19: How to update Gradle itself? - * https://github.com/jmfayard/buildSrcVersions/issues/19 - */ - const val gradleLatestVersion: String = "5.6.1" + /** + * + * See issue 19: How to update Gradle itself? + * https://github.com/jmfayard/buildSrcVersions/issues/19 + */ + const val gradleLatestVersion: String = "6.5.1" - const val gradleCurrentVersion: String = "5.6.1" + const val gradleCurrentVersion: String = "6.5" } /** @@ -62,5 +57,5 @@ object Versions { * https://github.com/jmfayard/buildSrcVersions/issues/47 */ val PluginDependenciesSpec.buildSrcVersions: PluginDependencySpec - inline get() = - id("de.fayard.buildSrcVersions").version(Versions.de_fayard_buildsrcversions_gradle_plugin) + inline get() = + id("de.fayard.buildSrcVersions").version(Versions.de_fayard_buildsrcversions_gradle_plugin) diff --git a/examples/counter/android/build.gradle.kts b/examples/counter/android/build.gradle.kts index 39ab5d9..3f40e81 100644 --- a/examples/counter/android/build.gradle.kts +++ b/examples/counter/android/build.gradle.kts @@ -34,7 +34,6 @@ android { } } - dependencies { implementation(Libs.kotlin_stdlib_jdk8) implementation(Libs.appcompat) diff --git a/examples/counter/android/src/main/java/org/reduxkotlin/example/counter/MainActivity.kt b/examples/counter/android/src/main/java/org/reduxkotlin/example/counter/MainActivity.kt index e3d7bcd..a02db3f 100644 --- a/examples/counter/android/src/main/java/org/reduxkotlin/example/counter/MainActivity.kt +++ b/examples/counter/android/src/main/java/org/reduxkotlin/example/counter/MainActivity.kt @@ -15,10 +15,9 @@ import org.reduxkotlin.examples.counter.reducer * This is NOT best practice for structuring a multiplatform App. */ - val store = createThreadSafeStore(reducer, 0) -class MainActivity: AppCompatActivity() { +class MainActivity : AppCompatActivity() { lateinit var storeSubscription: StoreSubscription override fun onCreate(savedInstanceState: Bundle?) { @@ -42,8 +41,11 @@ class MainActivity: AppCompatActivity() { } private fun incrementAsync() { - Handler().postDelayed({ - store.dispatch(Increment()) - }, 1000) + Handler().postDelayed( + { + store.dispatch(Increment()) + }, + 1000 + ) } -} \ No newline at end of file +} diff --git a/examples/counter/common/build.gradle b/examples/counter/common/build.gradle deleted file mode 100644 index 35468b1..0000000 --- a/examples/counter/common/build.gradle +++ /dev/null @@ -1,96 +0,0 @@ -repositories { - maven { url "https://dl.bintray.com/spekframework/spek-dev" } -} -apply plugin: 'java' -apply plugin: 'kotlin-multiplatform' - - -kotlin { - jvm() - js() { - [compileKotlinJs, compileTestKotlinJs].each { configuration -> - configuration.kotlinOptions { - moduleKind = 'umd' - sourceMap = true - metaInfo = true - } - } - } - - - iosArm64("ios") - iosX64("iosSim") - macosX64("macos") - mingwX64("win") - wasm32("wasm") - linuxArm32Hfp("linArm32") - linuxMips32("linMips32") - linuxMipsel32("linMipsel32") - linuxX64("lin64") - - sourceSets { - commonMain { - dependencies { - implementation kotlin("stdlib-common") - implementation project(":redux-kotlin") - } - } - commonTest { - kotlin.srcDir('src/test/kotlin') - dependencies { - implementation kotlin("test-common") - implementation kotlin("test-annotations-common") - implementation "org.spekframework.spek2:spek-dsl-metadata:$Versions.spek" - implementation "ch.tutteli.atrium:atrium-cc-en_GB-robstoll-common:$Versions.atrium" - implementation "io.mockk:mockk-common:$Versions.mockk" - } - } - - jvmMain { - kotlin.srcDir('src/jvmMain/kotlin') - dependencies { - implementation kotlin("stdlib") - } - } - jvmTest { - dependencies { - implementation kotlin("test") - implementation kotlin("test-junit") - implementation "org.spekframework.spek2:spek-dsl-jvm:$Versions.spek" - implementation "ch.tutteli.atrium:atrium-cc-en_GB-robstoll:$Versions.atrium" - implementation "io.mockk:mockk:$Versions.mockk" - - runtimeOnly "org.spekframework.spek2:spek-runner-junit5:$Versions.spek" - runtimeOnly 'org.jetbrains.kotlin:kotlin-reflect' - } - } - jsMain { - kotlin.srcDir('src/jsMain/kotlin') - dependencies { - implementation kotlin("stdlib-js") - } - compileKotlinJs { - kotlinOptions.metaInfo = true - kotlinOptions.sourceMap = true - kotlinOptions.verbose = true - kotlinOptions.main = "call" - kotlinOptions.moduleKind = "umd" - } - } - jsTest { - dependencies { - implementation kotlin("test-js") - implementation kotlin("stdlib-js") - } - } - - iosSimMain.dependsOn iosMain - iosSimTest.dependsOn iosTest - } -} - -jvmTest { - useJUnitPlatform { - includeEngines 'spek2' - } -} diff --git a/examples/counter/common/build.gradle.kts b/examples/counter/common/build.gradle.kts new file mode 100644 index 0000000..2ff0a18 --- /dev/null +++ b/examples/counter/common/build.gradle.kts @@ -0,0 +1,52 @@ +plugins { + java + kotlin("multiplatform") +} + +kotlin { + jvm() + js(IR) { + browser() + binaries.executable() + + listOf(compilations["main"], compilations["test"]).forEach { + with(it.kotlinOptions) { + moduleKind = "umd" + sourceMap = true + sourceMapEmbedSources = "always" + metaInfo = true + } + } + } + + iosArm64() + iosX64() + + sourceSets { + commonMain { + dependencies { + implementation(project(":redux-kotlin")) + } + } + commonTest { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + implementation("io.mockk:mockk-common:${Versions.io_mockk}") + } + } + val jvmTest by getting { + dependencies { + implementation(kotlin("test")) + implementation(kotlin("test-junit")) + runtimeOnly("org.jetbrains.kotlin:kotlin-reflect") + } + } + val jsTest by getting { + dependencies { + implementation(kotlin("test-js")) + implementation(kotlin("stdlib-js")) + } + } + } +} diff --git a/examples/counter/common/src/commonMain/kotlin/org/reduxkotlin/examples/counter/Reducer.kt b/examples/counter/common/src/commonMain/kotlin/org/reduxkotlin/examples/counter/Reducer.kt index a03912c..649d023 100644 --- a/examples/counter/common/src/commonMain/kotlin/org/reduxkotlin/examples/counter/Reducer.kt +++ b/examples/counter/common/src/commonMain/kotlin/org/reduxkotlin/examples/counter/Reducer.kt @@ -2,7 +2,6 @@ package org.reduxkotlin.examples.counter import org.reduxkotlin.Reducer - class Increment class Decrement @@ -23,4 +22,4 @@ val reducer: Reducer = { state, action -> is Decrement -> state - 1 else -> state } -} \ No newline at end of file +} diff --git a/examples/counter/common/src/test/kotlin/org/reduxkotlin/examples/counter/ReducerTest.kt b/examples/counter/common/src/test/kotlin/org/reduxkotlin/examples/counter/ReducerTest.kt index 3d1c5f8..704b85f 100644 --- a/examples/counter/common/src/test/kotlin/org/reduxkotlin/examples/counter/ReducerTest.kt +++ b/examples/counter/common/src/test/kotlin/org/reduxkotlin/examples/counter/ReducerTest.kt @@ -1,26 +1,22 @@ package org.reduxkotlin.examples.counter -import ch.tutteli.atrium.api.cc.en_GB.toBe -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe -import ch.tutteli.atrium.verbs.expect +import kotlin.test.Test +import kotlin.test.expect +class ReducerTest { -object CounterSpek : Spek({ - - describe("reducers") { - describe("counter") { - it("should handle INCREMENT action") { - expect(reducer(1, Increment())).toBe(2) - } + @Test + fun shouldHandleINCREMENTAction() { + expect(2) { reducer(1, Increment()) } + } - it("should handle DECREMENT action") { - expect(reducer(1, Decrement())).toBe(0) - } + @Test + fun shouldHandleDECREMENTAction() { + expect(0) { reducer(1, Decrement()) } + } - it("should ignore unknown actions") { - expect(reducer(1, Any())).toBe(1) - } - } + @Test + fun shouldIgnoreUnknownActions() { + expect(1) { reducer(1, Any()) } } -}) +} diff --git a/examples/todos/android/build.gradle.kts b/examples/todos/android/build.gradle.kts index 2a2de10..7a4b5b0 100644 --- a/examples/todos/android/build.gradle.kts +++ b/examples/todos/android/build.gradle.kts @@ -35,12 +35,11 @@ android { } } - dependencies { implementation(Libs.kotlin_stdlib_jdk8) implementation(Libs.appcompat) - implementation(Libs.constraintLayout) - implementation(Libs.recyclerView) + implementation(Libs.constraintlayout) + implementation(Libs.recyclerview) implementation(project(":examples:todos:common")) implementation(project(":redux-kotlin-threadsafe")) diff --git a/examples/todos/android/src/main/java/org/reduxkotlin/example/todos/MainActivity.kt b/examples/todos/android/src/main/java/org/reduxkotlin/example/todos/MainActivity.kt index bbc6a30..12c07bd 100644 --- a/examples/todos/android/src/main/java/org/reduxkotlin/example/todos/MainActivity.kt +++ b/examples/todos/android/src/main/java/org/reduxkotlin/example/todos/MainActivity.kt @@ -5,17 +5,20 @@ import androidx.appcompat.app.AppCompatActivity import kotlinx.android.synthetic.main.activity_main.* import org.reduxkotlin.StoreSubscription import org.reduxkotlin.createThreadSafeStore -import org.reduxkotlin.examples.todos.* +import org.reduxkotlin.examples.todos.AddTodo +import org.reduxkotlin.examples.todos.AppState +import org.reduxkotlin.examples.todos.SetVisibilityFilter +import org.reduxkotlin.examples.todos.VisibilityFilter +import org.reduxkotlin.examples.todos.rootReducer /** * This is a sample of basic redux behavior. * This is NOT best practice for structuring a multiplatform App. */ - val store = createThreadSafeStore(::rootReducer, AppState()) -class MainActivity: AppCompatActivity() { +class MainActivity : AppCompatActivity() { private lateinit var storeSubscription: StoreSubscription private var adapter = TodoAdapter() @@ -60,4 +63,4 @@ class MainActivity: AppCompatActivity() { btnActive.isSelected = false } } -} \ No newline at end of file +} diff --git a/examples/todos/android/src/main/java/org/reduxkotlin/example/todos/TodoAdapter.kt b/examples/todos/android/src/main/java/org/reduxkotlin/example/todos/TodoAdapter.kt index ab38bbf..7911b51 100644 --- a/examples/todos/android/src/main/java/org/reduxkotlin/example/todos/TodoAdapter.kt +++ b/examples/todos/android/src/main/java/org/reduxkotlin/example/todos/TodoAdapter.kt @@ -1,15 +1,15 @@ package org.reduxkotlin.example.todos +import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.item_todo.view.* import org.reduxkotlin.examples.todos.Todo import org.reduxkotlin.examples.todos.ToggleTodo -import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter class TodoAdapter : ListAdapter(DiffCallback()) { @@ -33,7 +33,7 @@ class TodoViewHolder(view: View) : RecyclerView.ViewHolder(view) { } itemView.tvTodo.text = "• ${todo.text}" - itemView.setOnClickListener { store.dispatch(ToggleTodo(adapterPosition))} + itemView.setOnClickListener { store.dispatch(ToggleTodo(adapterPosition)) } } } @@ -45,4 +45,4 @@ class DiffCallback : DiffUtil.ItemCallback() { override fun areContentsTheSame(oldItem: Todo, newItem: Todo): Boolean { return oldItem == newItem } -} \ No newline at end of file +} diff --git a/examples/todos/common/build.gradle b/examples/todos/common/build.gradle deleted file mode 100644 index 4e84145..0000000 --- a/examples/todos/common/build.gradle +++ /dev/null @@ -1,96 +0,0 @@ -repositories { - maven { url "https://dl.bintray.com/spekframework/spek-dev" } -} -apply plugin: 'java' -apply plugin: 'kotlin-multiplatform' - - -kotlin { - jvm() - js() { - [compileKotlinJs, compileTestKotlinJs].each { configuration -> - configuration.kotlinOptions { - moduleKind = 'umd' - sourceMap = true - metaInfo = true - } - } - } - - - iosArm64("ios") - iosX64("iosSim") - macosX64("macos") - mingwX64("win") - wasm32("wasm") - linuxArm32Hfp("linArm32") - linuxMips32("linMips32") - linuxMipsel32("linMipsel32") - linuxX64("lin64") - - sourceSets { - commonMain { - dependencies { - implementation kotlin("stdlib-common") - implementation project(":redux-kotlin-threadsafe") - } - } - commonTest { - kotlin.srcDir('src/test/kotlin') - dependencies { - implementation kotlin("test-common") - implementation kotlin("test-annotations-common") - implementation "org.spekframework.spek2:spek-dsl-metadata:$Versions.spek" - implementation "ch.tutteli.atrium:atrium-cc-en_GB-robstoll-common:$Versions.atrium" - implementation "io.mockk:mockk-common:$Versions.mockk" - } - } - - jvmMain { - kotlin.srcDir('src/jvmMain/kotlin') - dependencies { - implementation kotlin("stdlib") - } - } - jvmTest { - dependencies { - implementation kotlin("test") - implementation kotlin("test-junit") - implementation "org.spekframework.spek2:spek-dsl-jvm:$Versions.spek" - implementation "ch.tutteli.atrium:atrium-cc-en_GB-robstoll:$Versions.atrium" - implementation "io.mockk:mockk:1.9.3" - - runtimeOnly "org.spekframework.spek2:spek-runner-junit5:$Versions.spek" - runtimeOnly 'org.jetbrains.kotlin:kotlin-reflect' - } - } - jsMain { - kotlin.srcDir('src/jsMain/kotlin') - dependencies { - implementation kotlin("stdlib-js") - } - compileKotlinJs { - kotlinOptions.metaInfo = true - kotlinOptions.sourceMap = true - kotlinOptions.verbose = true - kotlinOptions.main = "call" - kotlinOptions.moduleKind = "umd" - } - } - jsTest { - dependencies { - implementation kotlin("test-js") - implementation kotlin("stdlib-js") - } - } - - iosSimMain.dependsOn iosMain - iosSimTest.dependsOn iosTest - } -} - -jvmTest { - useJUnitPlatform { - includeEngines 'spek2' - } -} diff --git a/examples/todos/common/build.gradle.kts b/examples/todos/common/build.gradle.kts new file mode 100644 index 0000000..f449f9b --- /dev/null +++ b/examples/todos/common/build.gradle.kts @@ -0,0 +1,54 @@ +plugins { + java + kotlin("multiplatform") +} + +kotlin { + iosArm32() + iosArm64() + iosX64() + js(IR) { + binaries.executable() + browser() + + listOf(compilations["main"], compilations["test"]).forEach { + with(it.kotlinOptions) { + moduleKind = "umd" + sourceMap = true + sourceMapEmbedSources = "always" + metaInfo = true + } + } + } + jvm() + + sourceSets { + commonMain { + dependencies { + implementation(project(":redux-kotlin")) + } + } + commonTest { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + implementation("io.mockk:mockk-common:${Versions.io_mockk}") + } + } + val jvmTest by getting { + dependencies { + implementation(kotlin("test")) + implementation(kotlin("test-junit")) + implementation("io.mockk:mockk:${Versions.io_mockk}") + + runtimeOnly("org.jetbrains.kotlin:kotlin-reflect") + } + } + val jsTest by getting { + dependencies { + implementation(kotlin("test-js")) + implementation(kotlin("stdlib-js")) + } + } + } +} diff --git a/examples/todos/common/src/commonMain/kotlin/org/reduxkotlin/examples/todos/AppState.kt b/examples/todos/common/src/commonMain/kotlin/org/reduxkotlin/examples/todos/AppState.kt index 336be0c..e88cfe6 100644 --- a/examples/todos/common/src/commonMain/kotlin/org/reduxkotlin/examples/todos/AppState.kt +++ b/examples/todos/common/src/commonMain/kotlin/org/reduxkotlin/examples/todos/AppState.kt @@ -1,6 +1,5 @@ package org.reduxkotlin.examples.todos - /** * Entire state tree for the app. */ diff --git a/examples/todos/common/src/test/kotlin/org/reduxkotlin/examples/todos/TodosReducerSpec.kt b/examples/todos/common/src/test/kotlin/org/reduxkotlin/examples/todos/TodosReducerSpec.kt index c0255ac..b24c49e 100644 --- a/examples/todos/common/src/test/kotlin/org/reduxkotlin/examples/todos/TodosReducerSpec.kt +++ b/examples/todos/common/src/test/kotlin/org/reduxkotlin/examples/todos/TodosReducerSpec.kt @@ -1,72 +1,53 @@ package org.reduxkotlin.examples.todos -import ch.tutteli.atrium.api.cc.en_GB.toBe -import ch.tutteli.atrium.verbs.expect -import io.mockk.impl.log.Logger -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe +import kotlin.test.Test +import kotlin.test.assertEquals -object TodosReducerSpec : Spek({ - describe("todos reducer") { - it("should handle AddToDo") { - expect( - todosReducer( - emptyList(), - AddTodo(text = "Run the tests") - ) - ).toBe( - listOf( - Todo( - text = "Run the tests", - completed = false, - id = 0 - ) +class TodosReducerSpec { + + @Test + fun shouldHandleAddToDo() { + assertEquals( + todosReducer( + emptyList(), + AddTodo(text = "Run the tests") + ), + listOf( + Todo( + text = "Run the tests", + completed = false, + id = 0 ) ) + ) - expect( - todosReducer( - listOf( - Todo( - text = "Run the tests", - completed = false, - id = 0 - ) - ), - AddTodo(text = "Use Redux") - ) - ).toBe( + assertEquals( + todosReducer( listOf( Todo( text = "Run the tests", completed = false, id = 0 - ), - Todo( - text = "Use Redux", - completed = false, - id = 1 ) + ), + AddTodo(text = "Use Redux") + ), + listOf( + Todo( + text = "Run the tests", + completed = false, + id = 0 + ), + Todo( + text = "Use Redux", + completed = false, + id = 1 ) ) + ) - expect( - todosReducer( - listOf( - Todo( - text = "Run the tests", - completed = false, - id = 0 - ), - Todo( - text = "Use Redux", - completed = false, - id = 1 - ) - ), - AddTodo(text = "Fix the tests") - ) - ).toBe( + assertEquals( + todosReducer( listOf( Todo( text = "Run the tests", @@ -77,37 +58,38 @@ object TodosReducerSpec : Spek({ text = "Use Redux", completed = false, id = 1 - ), - Todo( - text = "Fix the tests", - completed = false, - id = 2 ) + ), + AddTodo(text = "Fix the tests") + ), + listOf( + Todo( + text = "Run the tests", + completed = false, + id = 0 + ), + Todo( + text = "Use Redux", + completed = false, + id = 1 + ), + Todo( + text = "Fix the tests", + completed = false, + id = 2 ) ) - } + ) + } - it("should handle ToggleTodo") { - expect( - todosReducer( - listOf( - Todo( - text = "Run the tests", - completed = false, - id = 0 - ), - Todo( - text = "Use Redux", - completed = false, - id = 1 - ) - ), ToggleTodo(index = 0) - ) - ).toBe( + @Test + fun shouldHandleToggleTodo() { + assertEquals( + todosReducer( listOf( Todo( text = "Run the tests", - completed = true, + completed = false, id = 0 ), Todo( @@ -115,8 +97,21 @@ object TodosReducerSpec : Spek({ completed = false, id = 1 ) + ), + ToggleTodo(index = 0) + ), + listOf( + Todo( + text = "Run the tests", + completed = true, + id = 0 + ), + Todo( + text = "Use Redux", + completed = false, + id = 1 ) ) - } + ) } -}) +} diff --git a/gradle.properties b/gradle.properties index 3727253..cc7642a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,9 +19,11 @@ android.useAndroidX=true android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official +kotlin.native.ignoreDisabledTargets=true +kotlin.mpp.enableGranularSourceSetsMetadata=true GROUP=org.reduxkotlin -VERSION_NAME=0.5.3 +VERSION_NAME=0.5.5 POM_ARTIFACT_ID=reduxkotlin POM_DESCRIPTION=Redux implementation for Kotlin. Mulitiplatform supported. diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 50b57bf..8e9e2e9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-all.zip diff --git a/redux-kotlin-threadsafe/build.gradle b/redux-kotlin-threadsafe/build.gradle deleted file mode 100644 index 91faaae..0000000 --- a/redux-kotlin-threadsafe/build.gradle +++ /dev/null @@ -1,131 +0,0 @@ -repositories { - maven { url "https://dl.bintray.com/spekframework/spek-dev" } -} -apply plugin: 'java' -apply plugin: 'kotlin-multiplatform' -apply plugin: 'kotlinx-atomicfu' - -archivesBaseName = 'redux-kotlin-threadsafe' - -kotlin { - jvm() - js() { - [compileKotlinJs, compileTestKotlinJs].each { configuration -> - configuration.kotlinOptions { - moduleKind = 'umd' - sourceMap = true - metaInfo = true - } - } - } - - iosArm64("ios") - iosX64("iosSim") - macosX64("macos") - mingwX64("win") - //below are currently not supported by atomicfu - //wasm32("wasm") - //linuxArm32Hfp("linArm32") - //linuxMips32("linMips32") - //linuxMipsel32("linMipsel32") - linuxX64("lin64") - - sourceSets { - - commonMain { - dependencies { - implementation kotlin("stdlib-common") - api project(":redux-kotlin") - } - } - commonTest { - kotlin.srcDir('src/test/kotlin') - dependencies { - implementation kotlin("test-common") - implementation kotlin("test-annotations-common") - implementation Libs.spek_dsl_metadata - implementation Libs.atrium_cc_en_gb_robstoll_common - implementation Libs.mockk_common - implementation Libs.kotlin_coroutines - } - } - - jvmMain { - dependencies { - implementation kotlin("stdlib") - } - } - jvmTest { - dependencies { - implementation kotlin("test") - implementation kotlin("test-junit") - implementation Libs.kotlin_coroutines_test - implementation Libs.kotlin_coroutines_jvm - implementation Libs.spek_dsl_jvm - implementation Libs.atrium_cc_en_gb_robstoll - implementation Libs.mockk - - runtimeOnly Libs.spek_runner_junit5 - runtimeOnly Libs.kotlin_reflect - - } - } - jsMain { - dependencies { - implementation kotlin("stdlib-js") - } - compileKotlinJs { - kotlinOptions.metaInfo = true - kotlinOptions.sourceMap = true - kotlinOptions.suppressWarnings = true - kotlinOptions.verbose = true - kotlinOptions.main = "call" - kotlinOptions.moduleKind = "umd" - } - } - jsTest { - dependencies { - implementation kotlin("test-js") - implementation kotlin("stdlib-js") - } - } - - iosSimMain.dependsOn iosMain - iosSimTest.dependsOn iosTest - } -} - - -afterEvaluate { - // Alias the task names we use elsewhere to the new task names. - tasks.create('installMP').dependsOn('publishKotlinMultiplatformPublicationToMavenLocal') - tasks.create('installLocally') { - dependsOn 'publishKotlinMultiplatformPublicationToTestRepository' - dependsOn 'publishJvmPublicationToTestRepository' - dependsOn 'publishJsPublicationToTestRepository' - dependsOn 'publishMetadataPublicationToTestRepository' - } - tasks.create('installIosLocally') { - dependsOn 'publishKotlinMultiplatformPublicationToTestRepository' - dependsOn 'publishIosArm32PublicationToTestRepository' - dependsOn 'publishIosArm64PublicationToTestRepository' - dependsOn 'publishIosX64PublicationToTestRepository' - dependsOn 'publishMetadataPublicationToTestRepository' - } - // NOTE: We do not alias uploadArchives because CI runs it on Linux and we only want to run it on Mac OS. - //tasks.create('uploadArchives').dependsOn('publishKotlinMultiplatformPublicationToMavenRepository') -} - -apply from: rootProject.file('gradle/publish.gradle') - -publishing { - publications.all { - artifactId = artifactId.replace(project.name, 'redux-kotlin-threadsafe') - } -} - -jvmTest { - useJUnitPlatform { - includeEngines 'spek2' - } -} diff --git a/redux-kotlin-threadsafe/build.gradle.kts b/redux-kotlin-threadsafe/build.gradle.kts new file mode 100644 index 0000000..6d71e38 --- /dev/null +++ b/redux-kotlin-threadsafe/build.gradle.kts @@ -0,0 +1,101 @@ + +plugins { + java + kotlin("multiplatform") + id("kotlinx-atomicfu") +} + +kotlin { +// androidNativeArm32() +// androidNativeArm64() +// iosArm32() + iosArm64() + iosX64() + js(BOTH) { + browser() + nodejs() + + listOf(compilations["main"], compilations["test"]).forEach { + with(it.kotlinOptions) { + moduleKind = "umd" + sourceMap = true + sourceMapEmbedSources = "always" + metaInfo = true + } + } + } + jvm() + linuxX64() + macosX64() + mingwX64() +// mingwX86() + tvosArm64() + tvosX64() + watchosArm32() + watchosArm64() + watchosX86() + +// below are currently not supported by atomicfu +// wasm32("wasm") +// linuxArm32Hfp("linArm32") +// linuxMips32("linMips32") +// linuxMipsel32("linMipsel32") +// linuxArm64() + + sourceSets { + commonMain { + dependencies { + api(project(":redux-kotlin")) + } + } + commonTest { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + implementation(Libs.mockk_common) + implementation(Libs.kotlinx_coroutines_core) + } + } + val jvmTest by getting { + dependencies { + implementation(kotlin("test")) + implementation(kotlin("test-junit")) + implementation(Libs.kotlinx_coroutines_test) + implementation(Libs.kotlinx_coroutines_core_jvm) + implementation(Libs.mockk) + + runtimeOnly(Libs.kotlin_reflect) + } + } + val jsTest by getting { + dependencies { + implementation(kotlin("test-js")) + implementation(kotlin("stdlib-js")) + } + } + } +} + +afterEvaluate { + tasks { + // Alias the task names we use elsewhere to the new task names. + create("installMP").dependsOn("publishKotlinMultiplatformPublicationToMavenLocal") + create("installLocally") { + dependsOn("publishKotlinMultiplatformPublicationToTestRepository") + dependsOn("publishJvmPublicationToTestRepository") + dependsOn("publishJsPublicationToTestRepository") + dependsOn("publishMetadataPublicationToTestRepository") + } + create("installIosLocally") { + dependsOn("publishKotlinMultiplatformPublicationToTestRepository") + dependsOn("publishIosArm32PublicationToTestRepository") + dependsOn("publishIosArm64PublicationToTestRepository") + dependsOn("publishIosX64PublicationToTestRepository") + dependsOn("publishMetadataPublicationToTestRepository") + } + // NOTE: We do not alias uploadArchives because CI runs it on Linux and we only want to run it on Mac OS. + // tasks.create("uploadArchives").dependsOn("publishKotlinMultiplatformPublicationToMavenRepository") + } +} + +apply(from = rootProject.file("gradle/publish.gradle")) diff --git a/redux-kotlin-threadsafe/src/jvmTest/kotlin/org/reduxkotlin/util/CreateThreadSafeStoreSpec.kt b/redux-kotlin-threadsafe/src/jvmTest/kotlin/org/reduxkotlin/util/CreateThreadSafeStoreSpec.kt index 391ffa4..6057d97 100644 --- a/redux-kotlin-threadsafe/src/jvmTest/kotlin/org/reduxkotlin/util/CreateThreadSafeStoreSpec.kt +++ b/redux-kotlin-threadsafe/src/jvmTest/kotlin/org/reduxkotlin/util/CreateThreadSafeStoreSpec.kt @@ -1,44 +1,46 @@ package org.reduxkotlin.util -import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext +import org.junit.Test import org.reduxkotlin.createThreadSafeStore -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe import kotlin.system.measureTimeMillis import kotlin.test.assertEquals -object MultiThreadedSpec : Spek({ - describe("createStore") { - it("multithreaded increments massively") { - suspend fun massiveRun(action: suspend () -> Unit) { - val n = 100 // number of coroutines to launch - val k = 1000 // times an action is repeated by each coroutine - val time = measureTimeMillis { - coroutineScope { - // scope for coroutines - repeat(n) { - launch { - repeat(k) { action() } - } +class MultiThreadedClass { + @Test + fun multithreadedIncrementsMassively() { + suspend fun massiveRun(action: suspend () -> Unit) { + val n = 100 // number of coroutines to launch + val k = 1000 // times an action is repeated by each coroutine + val time = measureTimeMillis { + coroutineScope { + // scope for coroutines + repeat(n) { + launch { + repeat(k) { action() } } } } - println("Completed ${n * k} actions in $time ms") } + println("Completed ${n * k} actions in $time ms") + } - //NOTE: changing this to createStore() breaks the tests - val store = createThreadSafeStore(counterReducer, TestCounterState()) - runBlocking { - withContext(Dispatchers.Default) { - massiveRun { - store.dispatch(Increment()) - } + // NOTE: changing this to createStore() breaks the tests + val store = createThreadSafeStore(counterReducer, TestCounterState()) + runBlocking { + withContext(Dispatchers.Default) { + massiveRun { + store.dispatch(Increment()) } - assertEquals(100000, store.state.counter) } + assertEquals(100000, store.state.counter) } } -}) +} class Increment diff --git a/redux-kotlin/build.gradle b/redux-kotlin/build.gradle deleted file mode 100644 index 7b9a7b0..0000000 --- a/redux-kotlin/build.gradle +++ /dev/null @@ -1,146 +0,0 @@ -repositories { - maven { url "https://dl.bintray.com/spekframework/spek-dev" } -} -apply plugin: 'java' -apply plugin: 'kotlin-multiplatform' - -archivesBaseName = 'redux-kotlin' - -kotlin { - jvm() - js() { - [compileKotlinJs, compileTestKotlinJs].each { configuration -> - configuration.kotlinOptions { - moduleKind = 'umd' - sourceMap = true - metaInfo = true - } - } - } - - iosArm64("ios") - iosX64("iosSim") - macosX64("macos") - mingwX64("win") - wasm32("wasm") - linuxArm32Hfp("linArm32") - linuxMips32("linMips32") - linuxMipsel32("linMipsel32") - linuxX64("lin64") - - sourceSets { - - commonMain { - dependencies { - implementation kotlin("stdlib-common") - } - } - commonTest { - kotlin.srcDir('src/test/kotlin') - dependencies { - implementation kotlin("test-common") - implementation kotlin("test-annotations-common") - implementation Libs.spek_dsl_metadata - implementation Libs.atrium_cc_en_gb_robstoll_common - implementation Libs.mockk_common - } - } - - jvmMain { - kotlin.srcDir('src/jvmMain/kotlin') - dependencies { - implementation kotlin("stdlib") - } - } - jvmTest { - dependencies { - implementation kotlin("test") - implementation kotlin("test-junit") - implementation Libs.kotlin_coroutines_test - implementation Libs.kotlin_coroutines_jvm - implementation Libs.spek_dsl_jvm - implementation Libs.atrium_cc_en_gb_robstoll - implementation Libs.mockk - - runtimeOnly Libs.spek_runner_junit5 - runtimeOnly Libs.kotlin_reflect - } - } - jsMain { - kotlin.srcDir('src/jsMain/kotlin') - dependencies { - implementation kotlin("stdlib-js") - } - compileKotlinJs { - kotlinOptions.metaInfo = true - kotlinOptions.sourceMap = true - kotlinOptions.suppressWarnings = true - kotlinOptions.verbose = true - kotlinOptions.main = "call" - kotlinOptions.moduleKind = "umd" - } - } - jsTest { - dependencies { - implementation kotlin("test-js") - implementation kotlin("stdlib-js") - } - } - winMain { - kotlin.srcDir('src/fallbackMain') - } - wasmMain { - kotlin.srcDir('src/fallbackMain') - } - linArm32Main { - kotlin.srcDir('src/fallbackMain') - } - linMips32Main { - kotlin.srcDir('src/fallbackMain') - } - linMipsel32Main { - kotlin.srcDir('src/fallbackMain') - } - lin64Main { - kotlin.srcDir('src/fallbackMain') - } - - iosSimMain.dependsOn iosMain - iosSimTest.dependsOn iosTest - } -} - - -afterEvaluate { - // Alias the task names we use elsewhere to the new task names. - tasks.create('installMP').dependsOn('publishKotlinMultiplatformPublicationToMavenLocal') - tasks.create('installLocally') { - dependsOn 'publishKotlinMultiplatformPublicationToTestRepository' - dependsOn 'publishJvmPublicationToTestRepository' - dependsOn 'publishJsPublicationToTestRepository' - dependsOn 'publishMetadataPublicationToTestRepository' - } - tasks.create('installIosLocally') { - dependsOn 'publishKotlinMultiplatformPublicationToTestRepository' - dependsOn 'publishIosArm32PublicationToTestRepository' - dependsOn 'publishIosArm64PublicationToTestRepository' - dependsOn 'publishIosX64PublicationToTestRepository' - dependsOn 'publishMetadataPublicationToTestRepository' - } - // NOTE: We do not alias uploadArchives because CI runs it on Linux and we only want to run it on Mac OS. - //tasks.create('uploadArchives').dependsOn('publishKotlinMultiplatformPublicationToMavenRepository') -} - -apply from: rootProject.file('gradle/publish.gradle') - -publishing { - publications.all { - artifactId = artifactId.replace(project.name, 'redux-kotlin') - } -} - -jvmTest { - useJUnitPlatform { - includeEngines 'spek2' - } -} diff --git a/redux-kotlin/build.gradle.kts b/redux-kotlin/build.gradle.kts new file mode 100644 index 0000000..0de1cd4 --- /dev/null +++ b/redux-kotlin/build.gradle.kts @@ -0,0 +1,118 @@ +plugins { + java + kotlin("multiplatform") +} + +kotlin { + androidNativeArm32() + androidNativeArm64() + iosArm32() + iosArm64() + iosX64() + js(BOTH) { + browser() + nodejs() + + listOf(compilations["main"], compilations["test"]).forEach { + with(it.kotlinOptions) { + moduleKind = "umd" + sourceMap = true + sourceMapEmbedSources = "always" + metaInfo = true + } + } + } + jvm() + linuxArm32Hfp() + linuxArm64() + linuxMips32() + linuxMipsel32() + linuxX64() + macosX64() + mingwX64() + mingwX86() + tvosArm64() + tvosX64() + wasm32() + watchosArm32() + watchosArm64() + watchosX86() + + sourceSets { + commonTest { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + implementation(Libs.mockk_common) + } + } + + val fallback: (org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.() -> Unit) = { + kotlin.srcDir("src/fallbackMain") + } + val ios: (org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.() -> Unit) = { + kotlin.srcDir("src/iosMain/kotlin") + } + + val androidNativeArm32Main by getting(fallback) + val androidNativeArm64Main by getting(fallback) + val iosArm32Main by getting(ios) + val iosArm32Test by getting(ios) + val iosArm64Main by getting(ios) + val iosArm64Test by getting(ios) + val iosX64Main by getting(ios) + val linuxArm32HfpMain by getting(fallback) + val linuxArm64Main by getting(fallback) + val linuxMips32Main by getting(fallback) + val linuxMipsel32Main by getting(fallback) + val linuxX64Main by getting(fallback) + val jsTest by getting { + dependencies { + implementation(kotlin("test-js")) + } + } + val jvmTest by getting { + dependencies { + implementation(kotlin("test")) + implementation(kotlin("test-junit")) + implementation(Libs.kotlinx_coroutines_test) + implementation(Libs.kotlinx_coroutines_core_jvm) + implementation(Libs.mockk) + runtimeOnly(Libs.kotlin_reflect) + } + } + + val mingwX64Main by getting(fallback) + val mingwX86Main by getting(fallback) + val tvosArm64Main by getting(ios) + val tvosX64Main by getting(ios) + val wasm32Main by getting(fallback) + val watchosArm32Main by getting(ios) + val watchosArm64Main by getting(ios) + val watchosX86Main by getting(ios) + } +} + +afterEvaluate { + tasks { + // Alias the task names we use elsewhere to the new task names. + create("installMP").dependsOn("publishKotlinMultiplatformPublicationToMavenLocal") + create("installLocally") { + dependsOn("publishKotlinMultiplatformPublicationToTestRepository") + dependsOn("publishJvmPublicationToTestRepository") + dependsOn("publishJsPublicationToTestRepository") + dependsOn("publishMetadataPublicationToTestRepository") + } + create("installIosLocally") { + dependsOn("publishKotlinMultiplatformPublicationToTestRepository") + dependsOn("publishIosArm32PublicationToTestRepository") + dependsOn("publishIosArm64PublicationToTestRepository") + dependsOn("publishIosX64PublicationToTestRepository") + dependsOn("publishMetadataPublicationToTestRepository") + } + // NOTE: We do not alias uploadArchives because CI runs it on Linux and we only want to run it on Mac OS. + // tasks.create("uploadArchives").dependsOn("publishKotlinMultiplatformPublicationToMavenRepository") + } +} + +apply(from = rootProject.file("gradle/publish.gradle")) diff --git a/redux-kotlin/proguard-rules.pro b/redux-kotlin/proguard-rules.pro index f1b4245..2f9dc5a 100644 --- a/redux-kotlin/proguard-rules.pro +++ b/redux-kotlin/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. +# proguardFiles setting in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html diff --git a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Action.kt b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/ActionTypes.kt similarity index 99% rename from redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Action.kt rename to redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/ActionTypes.kt index 0ead87f..5fd5bb8 100644 --- a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Action.kt +++ b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/ActionTypes.kt @@ -10,4 +10,3 @@ object ActionTypes { */ object REPLACE } - diff --git a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/ApplyMiddleware.kt b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/ApplyMiddleware.kt index 0399493..f5c118b 100644 --- a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/ApplyMiddleware.kt +++ b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/ApplyMiddleware.kt @@ -24,7 +24,8 @@ fun applyMiddleware(vararg middlewares: Middleware): StoreEnhance val dispatch: Dispatcher = { throw Exception( """Dispatching while constructing your middleware is not allowed. - Other middleware would not be applied to this dispatch.""") + Other middleware would not be applied to this dispatch.""" + ) } store.dispatch = dispatch val chain = middlewares.map { middleware -> middleware(store) } diff --git a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Compose.kt b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Compose.kt index dbd278d..e72ba90 100644 --- a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Compose.kt +++ b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Compose.kt @@ -4,7 +4,7 @@ package org.reduxkotlin * Composes a list of single argument functions from right to left. */ fun compose(vararg functions: (T) -> T): (T) -> T = - { x -> functions.foldRight(x, { f, composed -> f(composed) }) } + { x -> functions.foldRight(x, { f, composed -> f(composed) }) } fun compose(functions: List<(T) -> T>): (T) -> T = - { x -> functions.foldRight(x, { f, composed -> f(composed) }) } + { x -> functions.foldRight(x, { f, composed -> f(composed) }) } diff --git a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/CreateStore.kt b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/CreateStore.kt index b07945d..ade9f22 100644 --- a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/CreateStore.kt +++ b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/CreateStore.kt @@ -241,6 +241,5 @@ fun createStore( override var dispatch: Dispatcher = ::dispatch override val subscribe = ::subscribe override val replaceReducer = ::replaceReducer - } } diff --git a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Definitions.kt b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Definitions.kt index f218998..2443067 100644 --- a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Definitions.kt +++ b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/Definitions.kt @@ -1,6 +1,5 @@ package org.reduxkotlin - /** * See also https://github.com/reactjs/redux/blob/master/docs/Glossary.md#reducer */ @@ -34,7 +33,6 @@ typealias StoreEnhancer = (StoreCreator) -> StoreCreator */ typealias Middleware = (store: Store) -> (next: Dispatcher) -> (action: Any) -> Any - interface Store { val getState: GetState var dispatch: Dispatcher @@ -58,7 +56,6 @@ fun middleware(dispatch: (Store, next: Dispatcher, action: Any) - } } - /** * Convenience function for creating a [ReducerForActionType] * usage: diff --git a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/utils/IsPlainObject.kt b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/utils/IsPlainObject.kt index 980901e..dde90c4 100644 --- a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/utils/IsPlainObject.kt +++ b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/utils/IsPlainObject.kt @@ -1,3 +1,3 @@ package org.reduxkotlin.utils -fun isPlainObject(obj: Any) = obj !is Function<*> \ No newline at end of file +fun isPlainObject(obj: Any) = obj !is Function<*> diff --git a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/utils/ThreadUtil.kt b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/utils/ThreadUtil.kt index 700a6da..1d7f695 100644 --- a/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/utils/ThreadUtil.kt +++ b/redux-kotlin/src/commonMain/kotlin/org/reduxkotlin/utils/ThreadUtil.kt @@ -14,5 +14,5 @@ expect fun getThreadName(): String fun stripCoroutineName(threadName: String): String { val lastIndex = threadName.lastIndexOf('@') return if (lastIndex < 0) threadName - else threadName.substring(0, lastIndex) + else threadName.substring(0, lastIndex) } diff --git a/redux-kotlin/src/commonTest/kotlin/org/reduxkotlin/ApplyMiddlewareTest.kt b/redux-kotlin/src/commonTest/kotlin/org/reduxkotlin/ApplyMiddlewareTest.kt new file mode 100644 index 0000000..faf1d0f --- /dev/null +++ b/redux-kotlin/src/commonTest/kotlin/org/reduxkotlin/ApplyMiddlewareTest.kt @@ -0,0 +1,76 @@ +package org.reduxkotlin + +import kotlin.test.Test +import kotlin.test.assertFails + +class ApplyMiddlewareSpec { + @Test + fun warnsWhenDispatchingDuringMiddlewareSetup() { + fun dispatchingMiddleware(store: Store): (next: Dispatcher) -> (action: Any) -> Any { + store.dispatch(AddTodo("1", "Dont dispatch in middleware setup")) + return { next -> + { action -> + { + next(action) + } + } + } + } + + assertFails { + val storeEnhancer: StoreEnhancer = applyMiddleware(::dispatchingMiddleware) + createStore(todos, TestState(), storeEnhancer) + } + } + + /* + it("wraps dispatch method with middleware once") { + fun test(spyOnMethods) { + return methods => { + spyOnMethods(methods) + return next => action => next(action) + } + } + + val spy = jest.fn() + val store = applyMiddleware (test(spy), thunk)(createStore)(reducers.todos) + store.dispatch(AddTodo("Use Redux")) + store.dispatch(AddTodo("Flux FTW!")) + + expect(spy.mock.calls.length).toBe(1) + + expect(spy.mock.calls[0][0]).toHaveProperty("getState") + expect(spy.mock.calls[0][0]).toHaveProperty("dispatch") + + expect(store.getState()).toEqual([ + { id: 1, text: "Use Redux" }, + { id: 2, text: "Flux FTW!" } + ]) + }) + + */ +} + +/************** Test Reducer & actions - tobe moved into example app *********/ + +data class AddTodo(val id: String, val text: String) +data class ToggleTodo(val id: String) +data class Todo(val id: String, val text: String, val completed: Boolean = false) + +data class TestState(val todos: List = listOf()) + +val todos = { state: TestState, action: Any -> + when (action) { + is AddTodo -> state.copy(todos = state.todos.plus(Todo(action.id, action.text, false))) + is ToggleTodo -> state.copy( + todos = state.todos.map { + if (it.id == action.id) { + it.copy(completed = !it.completed) + } else { + it + } + } + ) + else -> state + } +} diff --git a/redux-kotlin/src/commonTest/kotlin/org/reduxkotlin/CreateStoreSpec.kt b/redux-kotlin/src/commonTest/kotlin/org/reduxkotlin/CreateStoreSpec.kt new file mode 100644 index 0000000..9423be4 --- /dev/null +++ b/redux-kotlin/src/commonTest/kotlin/org/reduxkotlin/CreateStoreSpec.kt @@ -0,0 +1,129 @@ +package org.reduxkotlin + +import kotlin.test.Test +import kotlin.test.assertEquals + +class CreateStoreSpec { + @Test + fun passesTheInitialState() { + val store = createStore( + todos, + TestState( + listOf( + Todo( + id = "1", + text = "Hello" + ) + ) + ) + ) + + assertEquals( + store.getState(), + TestState( + listOf( + Todo( + id = "1", + text = "Hello" + ) + ) + ) + ) + } + + @Test + fun appliesTheReducerToThePreviousState() { + val store = createStore(todos, TestState()) + assertEquals(store.getState(), TestState()) + + store.dispatch(Any()) + assertEquals(store.getState(), TestState()) + + store.dispatch(AddTodo("1", "Hello")) + assertEquals( + store.getState(), + TestState( + listOf( + Todo( + id = "1", + text = "Hello" + ) + ) + ) + ) + + // TODO are ids autoincrement? + store.dispatch(AddTodo("2", "World")) + assertEquals( + store.getState(), + TestState( + listOf( + Todo( + id = "1", + text = "Hello" + ), + Todo( + id = "2", + text = "World" + ) + ) + ) + ) + } + + @Test + fun appliesTheReducerToTheInitialState() { + val store = createStore( + todos, + TestState( + listOf( + Todo( + id = "1", + text = "Hello" + ) + ) + ) + ) + assertEquals( + store.getState(), + TestState( + listOf( + Todo( + id = "1", + text = "Hello" + ) + ) + ) + ) + + store.dispatch(Any()) + assertEquals( + store.getState(), + TestState( + listOf( + Todo( + id = "1", + text = "Hello" + ) + ) + ) + ) + + store.dispatch(AddTodo("2", "World")) + assertEquals( + store.getState(), + TestState( + listOf( + Todo( + id = "1", + text = "Hello" + ), + Todo( + id = "2", + text = "World" + ) + ) + ) + ) + } +} diff --git a/redux-kotlin/src/jsMain/kotlin/org/reduxkotlin/utils/ThreadUtil.kt b/redux-kotlin/src/jsMain/kotlin/org/reduxkotlin/utils/ThreadUtil.kt index 8603350..d81cf43 100644 --- a/redux-kotlin/src/jsMain/kotlin/org/reduxkotlin/utils/ThreadUtil.kt +++ b/redux-kotlin/src/jsMain/kotlin/org/reduxkotlin/utils/ThreadUtil.kt @@ -1,3 +1,3 @@ package org.reduxkotlin.utils -actual fun getThreadName() = "main" \ No newline at end of file +actual fun getThreadName() = "main" diff --git a/redux-kotlin/src/jvmTest/kotlin/org/reduxkotlin/util/CreateSameThreadEnforcedStoreSpec.kt b/redux-kotlin/src/jvmTest/kotlin/org/reduxkotlin/util/CreateSameThreadEnforcedStoreSpec.kt index ff3e4ec..768f294 100644 --- a/redux-kotlin/src/jvmTest/kotlin/org/reduxkotlin/util/CreateSameThreadEnforcedStoreSpec.kt +++ b/redux-kotlin/src/jvmTest/kotlin/org/reduxkotlin/util/CreateSameThreadEnforcedStoreSpec.kt @@ -1,25 +1,47 @@ package org.reduxkotlin.util -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.launch +import kotlinx.coroutines.newSingleThreadContext +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.setMain -import org.reduxkotlin.* -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe +import kotlinx.coroutines.withContext +import org.junit.Test +import org.reduxkotlin.Reducer +import org.reduxkotlin.Store +import org.reduxkotlin.TestState +import org.reduxkotlin.Todo +import org.reduxkotlin.applyMiddleware +import org.reduxkotlin.createSameThreadEnforcedStore +import org.reduxkotlin.middleware +import org.reduxkotlin.todos import java.util.concurrent.CountDownLatch import java.util.concurrent.Executors -import kotlin.IllegalStateException import kotlin.system.measureTimeMillis -import kotlin.test.* - -object CreateSameThreadEnforcedStoreSpec : Spek({ - val mainThreadSurrogate = Executors.newSingleThreadExecutor().asCoroutineDispatcher() - Dispatchers.setMain(mainThreadSurrogate) - - describe("createStore") { - val store = createSameThreadEnforcedStore( - todos, TestState( +import kotlin.test.BeforeTest +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class CreateSameThreadEnforcedStoreSpec { + lateinit var store: Store + + @BeforeTest + fun before() { + val mainThreadSurrogate = Executors.newSingleThreadExecutor().asCoroutineDispatcher() + Dispatchers.setMain(mainThreadSurrogate) + + store = createSameThreadEnforcedStore( + todos, + TestState( listOf( Todo( id = "1", @@ -28,75 +50,85 @@ object CreateSameThreadEnforcedStoreSpec : Spek({ ) ) ) + } - it("ensure same thread on getState") { - ensureSameThread { store.getState() } - } - it("ensure same thread on dispatch") { - ensureSameThread { store.dispatch(Any()) } - } - it("ensure same thread on replaceReducer") { - ensureSameThread { store.replaceReducer { state, action -> state } } - } - it("ensure same thread on subscribe") { - ensureSameThread { store.subscribe { } } - } - it("enforces same thread when thread name appends coroutine name") { - val middleware = TestMiddleware() - - runBlocking { - CoroutineScope(Dispatchers.Main).async { - val store = createSameThreadEnforcedStore( - testReducer, - TestState(), - applyMiddleware(middleware.middleware) - ) + @Test + fun ensureSameThreadOnGetState() { + ensureSameThread { store.getState() } + } - store.dispatch(Any()) - }.await() - Thread.sleep(2000) - assertFalse(middleware.failed) - } + @Test + fun ensureSameThreadOnDispatch() { + ensureSameThread { store.dispatch(Any()) } + } + + @Test + fun ensureSameThreadOnReplaceReducer() { + ensureSameThread { store.replaceReducer { state, action -> state } } + } + + @Test + fun ensureSameThreadOnSubscribe() { + ensureSameThread { store.subscribe { } } + } + + @Test + fun enforcesSameThreadWhenThreadNameAppendsCoroutineName() { + val middleware = TestMiddleware() + + runBlocking { + CoroutineScope(Dispatchers.Main).async { + val store = createSameThreadEnforcedStore( + testReducer, + TestState(), + applyMiddleware(middleware.middleware) + ) + + store.dispatch(Any()) + }.await() + Thread.sleep(2000) + assertFalse(middleware.failed) } - it("increments massively") { - suspend fun massiveRun(action: suspend () -> Unit) { - val n = 100 // number of coroutines to launch - val k = 1000 // times an action is repeated by each coroutine - val time = measureTimeMillis { - coroutineScope { - // scope for coroutines - repeat(n) { - launch { - repeat(k) { action() } - } + } + + @Test + fun incrementsMassively() { + suspend fun massiveRun(action: suspend () -> Unit) { + val n = 100 // number of coroutines to launch + val k = 1000 // times an action is repeated by each coroutine + val time = measureTimeMillis { + coroutineScope { + // scope for coroutines + repeat(n) { + launch { + repeat(k) { action() } } } } - println("Completed ${n * k} actions in $time ms") } + println("Completed ${n * k} actions in $time ms") + } + val counterContext = newSingleThreadContext("CounterContext") - val counterContext = newSingleThreadContext("CounterContext") - - lateinit var store: Store - runBlocking { - withContext(counterContext) { - store = createSameThreadEnforcedStore(counterReducer, TestCounterState()) - } + lateinit var store: Store + runBlocking { + withContext(counterContext) { + store = createSameThreadEnforcedStore(counterReducer, TestCounterState()) } - runBlocking { - withContext(counterContext) { - massiveRun { - store.dispatch(Increment()) - } - } - withContext(counterContext) { - assertEquals(100000, store.state.counter) + } + runBlocking { + withContext(counterContext) { + massiveRun { + store.dispatch(Increment()) } } + withContext(counterContext) { + assertEquals(100000, store.state.counter) + } } } -}) +} private fun ensureSameThread(testFun: () -> Any) { val latch = CountDownLatch(1) diff --git a/redux-kotlin/src/macosMain/kotlin/org/reduxkotlin/utils/ThreadUtilMacOs.kt b/redux-kotlin/src/macosX64Main/kotlin/org/reduxkotlin/utils/ThreadUtilMacOs.kt similarity index 100% rename from redux-kotlin/src/macosMain/kotlin/org/reduxkotlin/utils/ThreadUtilMacOs.kt rename to redux-kotlin/src/macosX64Main/kotlin/org/reduxkotlin/utils/ThreadUtilMacOs.kt diff --git a/redux-kotlin/src/test/kotlin/org/reduxkotlin/ApplyMiddlewareTest.kt b/redux-kotlin/src/test/kotlin/org/reduxkotlin/ApplyMiddlewareTest.kt deleted file mode 100644 index 617e659..0000000 --- a/redux-kotlin/src/test/kotlin/org/reduxkotlin/ApplyMiddlewareTest.kt +++ /dev/null @@ -1,82 +0,0 @@ -package org.reduxkotlin - -import ch.tutteli.atrium.api.cc.en_GB.toThrow -import ch.tutteli.atrium.domain.creating.AnyAssertions -import ch.tutteli.atrium.verbs.expect -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe - - -object ApplyMiddlewareSpec : Spek({ - describe("applyMiddleware") { - it("warns when dispatching during middleware setup") { - fun dispatchingMiddleware(store: Store): (next: Dispatcher) -> (action: Any) -> Any { - store.dispatch(AddTodo("1", "Dont dispatch in middleware setup")); - return { next -> - { action -> - { - next(action) - } - } - } - } - - expect { - val storeEnhancer: StoreEnhancer = applyMiddleware(::dispatchingMiddleware) - createStore(todos, TestState(), storeEnhancer) - }.toThrow {} - } - - /* - it("wraps dispatch method with middleware once") { - fun test(spyOnMethods) { - return methods => { - spyOnMethods(methods) - return next => action => next(action) - } - } - - val spy = jest.fn() - val store = applyMiddleware (test(spy), thunk)(createStore)(reducers.todos) - - store.dispatch(AddTodo("Use Redux")) - store.dispatch(AddTodo("Flux FTW!")) - - expect(spy.mock.calls.length).toBe(1) - - expect(spy.mock.calls[0][0]).toHaveProperty("getState") - expect(spy.mock.calls[0][0]).toHaveProperty("dispatch") - - expect(store.getState()).toEqual([ - { id: 1, text: "Use Redux" }, - { id: 2, text: "Flux FTW!" } - ]) - }) - - */ - - } -}) - -/************** Test Reducer & actions - tobe moved into example app *********/ - -data class AddTodo(val id: String, val text: String) -data class ToggleTodo(val id: String) -data class Todo(val id: String, val text: String, val completed: Boolean = false) - -data class TestState(val todos: List = listOf()) - -val todos = { state: TestState, action: Any -> - when (action) { - is AddTodo -> state.copy(todos = state.todos.plus(Todo(action.id, action.text, false))) - is ToggleTodo -> state.copy(todos = state.todos.map { - if (it.id == action.id) { - it.copy(completed = !it.completed) - } else { - it - } - }) - else -> state - } - } - diff --git a/redux-kotlin/src/test/kotlin/org/reduxkotlin/CreateStoreSpec.kt b/redux-kotlin/src/test/kotlin/org/reduxkotlin/CreateStoreSpec.kt deleted file mode 100644 index 98217d7..0000000 --- a/redux-kotlin/src/test/kotlin/org/reduxkotlin/CreateStoreSpec.kt +++ /dev/null @@ -1,122 +0,0 @@ -package org.reduxkotlin - -import ch.tutteli.atrium.api.cc.en_GB.toBe -import ch.tutteli.atrium.verbs.expect -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe - -object CreateStoreSpec : Spek({ - describe("createStore") { - it("passes the initial state") { - val store = createStore( - todos, TestState( - listOf( - Todo( - id = "1", - text = "Hello" - ) - ) - ) - ) - - expect(store.getState()).toBe( - TestState( - listOf( - Todo( - id = "1", - text = "Hello" - ) - ) - ) - ) - } - it("applies the reducer to the previous state") { - val store = createStore(todos, TestState()) - expect(store.getState()).toBe(TestState()) - - store.dispatch(Any()) - expect(store.getState()).toBe(TestState()) - - store.dispatch(AddTodo("1", "Hello")) - expect(store.getState()).toBe( - TestState( - listOf( - Todo( - id = "1", - text = "Hello" - ) - ) - ) - ) - - //TODO are ids autoincrement? - store.dispatch(AddTodo("2", "World")) - expect(store.getState()).toBe( - TestState( - listOf( - Todo( - id = "1", - text = "Hello" - ), - Todo( - id = "2", - text = "World" - ) - ) - ) - ) - } - - it("applies the reducer to the initial state") { - val store = createStore( - todos, TestState( - listOf( - Todo( - id = "1", - text = "Hello" - ) - ) - ) - ) - expect(store.getState()).toBe( - TestState( - listOf( - Todo( - id = "1", - text = "Hello" - ) - ) - ) - ) - - store.dispatch(Any()) - expect(store.getState()).toBe( - TestState( - listOf( - Todo( - id = "1", - text = "Hello" - ) - ) - ) - ) - - store.dispatch(AddTodo("2", "World")) - expect(store.getState()).toBe( - TestState( - listOf( - Todo( - id = "1", - text = "Hello" - ), - Todo( - id = "2", - text = "World" - ) - ) - ) - ) - } - - } -}) diff --git a/settings.gradle b/settings.gradle.kts similarity index 50% rename from settings.gradle rename to settings.gradle.kts index e37467e..6b34c57 100644 --- a/settings.gradle +++ b/settings.gradle.kts @@ -9,14 +9,12 @@ pluginManagement { } include( - ':redux-kotlin', - ':redux-kotlin-threadsafe', - ':examples:counter:common', - ':examples:counter:android', - ':examples:todos:common', - ':examples:todos:android' + ":redux-kotlin", + ":redux-kotlin-threadsafe", + ":examples:counter:common", + ":examples:counter:android", + ":examples:todos:common", + ":examples:todos:android" ) -rootProject.name = 'Redux-Kotlin' - -enableFeaturePreview('GRADLE_METADATA') +rootProject.name = "Redux-Kotlin"