Skip to content

Commit

Permalink
Solve #33 in CompositeKnot (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergej Shafarenka authored Apr 22, 2020
1 parent f8cd90f commit a9c1e4f
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 13 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {

allprojects {
group = "de.halfbit"
version = "3.1.0"
version = "3.1.1"

repositories {
mavenCentral()
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Deps.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
object Deps {

object Version {
const val kotlin = "1.3.71"
const val kotlin = "1.3.72"
const val dokka = "0.9.17"
const val jvmTarget = "1.8"
const val agp = "3.5.3"
Expand Down
3 changes: 2 additions & 1 deletion knot3/src/main/kotlin/de/halfbit/knot3/CompositeKnot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.reactivex.rxjava3.core.Scheduler
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.functions.Consumer
import io.reactivex.rxjava3.plugins.RxJavaPlugins
import io.reactivex.rxjava3.subjects.BehaviorSubject
import io.reactivex.rxjava3.subjects.PublishSubject
import io.reactivex.rxjava3.subjects.Subject
Expand Down Expand Up @@ -153,7 +154,7 @@ internal class DefaultCompositeKnot<State : Any>(
.intercept(composition.stateInterceptors)
.subscribe(
stateSubject::onNext,
stateSubject::onError
RxJavaPlugins::onError
)
)
maybeSubscribeColdEvents()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package de.halfbit.knot3

import com.google.common.truth.Truth.assertThat
import de.halfbit.knot3.utils.RxPluginsException
import io.reactivex.rxjava3.subjects.PublishSubject
import org.junit.Rule
import org.junit.Test
import java.util.concurrent.atomic.AtomicInteger

class CompositeKnotColdSourceTest {

@Rule
@JvmField
var rxPluginsException: RxPluginsException = RxPluginsException.none()

private data class State(val value: String)
private sealed class Change {
object A : Change()
Expand Down Expand Up @@ -263,11 +269,9 @@ class CompositeKnotColdSourceTest {
}
}

rxPluginsException.expect(givenError)
knot.compose()

val observer = knot.state.test()
knot.state.test()
source.onNext("event")

observer.assertError(givenError)
}
}
45 changes: 39 additions & 6 deletions knot3/src/test/kotlin/de/halfbit/knot3/PrimeTest.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package de.halfbit.knot3

import com.google.common.truth.Truth.assertThat
import de.halfbit.knot3.utils.RxPluginsException
import de.halfbit.knot3.utils.SchedulerTester
import io.reactivex.rxjava3.schedulers.Schedulers
import io.reactivex.rxjava3.subjects.PublishSubject
import org.junit.Rule
import org.junit.Test

class PrimeTest {

@Rule
@JvmField
var rxPluginsException: RxPluginsException = RxPluginsException.none()

private data class State(val value: String)

private sealed class Change(val value: String) {
Expand All @@ -23,16 +29,26 @@ class PrimeTest {
}

@Test
fun `CompositeKnot emits IllegalStateException if reducer cannot be found`() {
fun `Exception thrown if reducer cannot be found when no state observers`() {
val knot = compositeKnot<State> {
state { initial = State("empty") }
}

val observer = knot.state.test()
rxPluginsException.expect(IllegalStateException::class)
knot.compose()
knot.change.accept(Change.A)
}

@Test
fun `Exception thrown if reducer cannot be found when one state observer`() {
val knot = compositeKnot<State> {
state { initial = State("empty") }
}

observer.assertError(IllegalStateException::class.java)
rxPluginsException.expect(IllegalStateException::class)
knot.state.test()
knot.compose()
knot.change.accept(Change.A)
}

@Test
Expand Down Expand Up @@ -320,7 +336,7 @@ class PrimeTest {
}

@Test
fun `Reducer throws error on unexpected()`() {
fun `Exception throw in reducer gets propagated when no state observers`() {
val knot = compositeKnot<State> {
state { initial = State("empty") }
}
Expand All @@ -331,10 +347,27 @@ class PrimeTest {
}
}

val observer = knot.state.test()
rxPluginsException.expect(IllegalStateException::class)
knot.compose()
knot.change.accept(Change.A)
}

@Test
fun `Exception throw in reducer gets propagated when one state observer`() {
val knot = compositeKnot<State> {
state { initial = State("empty") }
}

knot.registerPrime<Change, Action> {
changes {
reduce<Change.A> { unexpected(it) }
}
}

rxPluginsException.expect(IllegalStateException::class)
knot.state.test()
knot.compose()
knot.change.accept(Change.A)
observer.assertError(IllegalStateException::class.java)
}

@Test
Expand Down
57 changes: 57 additions & 0 deletions knot3/src/test/kotlin/de/halfbit/knot3/utils/RxPluginsException.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package de.halfbit.knot3.utils

import io.reactivex.rxjava3.plugins.RxJavaPlugins
import org.hamcrest.core.IsEqual
import org.junit.Assert
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
import kotlin.reflect.KClass

class RxPluginsException private constructor() : TestRule {

private var expectedType: KClass<*>? = null
private var expectedInstance: Throwable? = null

fun expect(type: KClass<*>) {
expectedType = type
}

fun expect(instance: Throwable) {
expectedInstance = instance
}

override fun apply(base: Statement, description: Description): Statement {
return ExpectedExceptionStatement(base)
}

private inner class ExpectedExceptionStatement(
private val base: Statement
) : Statement() {
override fun evaluate() {
var observedException: Throwable? = null
val backup = RxJavaPlugins.getErrorHandler()
RxJavaPlugins.setErrorHandler {
observedException = it
}
try {
base.evaluate()
} finally {
RxJavaPlugins.setErrorHandler(backup)
}
when {
expectedInstance != null -> {
Assert.assertThat(observedException, IsEqual(expectedInstance))
}
expectedType != null -> {
val observedType = observedException?.let { it::class }
Assert.assertThat(observedType, IsEqual(expectedType))
}
}
}
}

companion object {
fun none() = RxPluginsException()
}
}

0 comments on commit a9c1e4f

Please sign in to comment.