Skip to content

Commit

Permalink
Increase test module coverage. (#387)
Browse files Browse the repository at this point in the history
* Increase test module coverage.

* Make multipleValueStream() private.
  • Loading branch information
Laimiux authored Sep 10, 2024
1 parent ab84f7d commit 45666a3
Show file tree
Hide file tree
Showing 17 changed files with 289 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import io.reactivex.rxjava3.subjects.BehaviorSubject
class RxJavaFormulaTestDelegate<Input : Any, Output : Any, FormulaT : IFormula<Input, Output>>(
override val formula: FormulaT,
isValidationEnabled: Boolean = true,
inspector: Inspector? = null,
dispatcher: Dispatcher? = null,
inspector: Inspector?,
dispatcher: Dispatcher?,
) : FormulaTestDelegate<Input, Output, FormulaT> {
private val runtimeConfig = RuntimeConfig(
isValidationEnabled = isValidationEnabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class TestActionObserver<Event>(private val action: Action<Event>) {
* provide a [Cancelable].
*/
fun cancel() {
cancelation!!.cancel()
val cancelable = cancelation ?: run {
throw IllegalStateException("Action did not return a cancelable.")
}

cancelable.cancel()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class TestCallback : () -> Unit {
}

fun assertTimesCalled(times: Int) {
assert(invocationCount == times) {
"Expected: $times, was: $invocationCount"
if (invocationCount != times) {
throw AssertionError("Expected: $times, was: $invocationCount")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class TestFormulaObserver<Input : Any, Output : Any, FormulaT : IFormula<Input,
assertNoErrors() // Check after interaction
}

inline fun output(assert: Output.() -> Unit) = apply {
fun output(assert: Output.() -> Unit) = apply {
ensureFormulaIsRunning()
assertNoErrors() // Check before interaction
assert(values().last())
Expand All @@ -39,8 +39,9 @@ class TestFormulaObserver<Input : Any, Output : Any, FormulaT : IFormula<Input,
ensureFormulaIsRunning()
assertNoErrors()
val size = values().size
assert(size == count) {
"Expected: $count, was: $size"

if (size != count) {
throw AssertionError("Expected: $count, was: $size")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class TestListener<Event> : Listener<Event> {

fun assertTimesCalled(times: Int) {
val timesCalled = values.size
assert(timesCalled == times) {
"Expected: $times, was: $timesCalled"
if (timesCalled != times) {
throw AssertionError("Expected: $times, was: $timesCalled")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,5 @@ fun <Input : Any, Output : Any, F: IFormula<Input, Output>> F.test(
return TestFormulaObserver(delegate)
}

/**
* An extension function to create a [TestFormulaObserver] for a [IFormula] instance.
*
* @param initialInput Input passed to [IFormula].
*/
fun <Input : Any, Output : Any, F: IFormula<Input, Output>> F.test(
initialInput: Input,
isValidationEnabled: Boolean = true,
inspector: Inspector? = null,
dispatcher: Dispatcher? = null,
): TestFormulaObserver<Input, Output, F> {
return test(isValidationEnabled, inspector, dispatcher).apply {
input(initialInput)
}
}

fun <Event> Action<Event>.test() = TestActionObserver(this)

Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.instacart.formula.test

import com.google.common.truth.Truth
import com.instacart.formula.Evaluation
import com.instacart.formula.Snapshot
import com.instacart.formula.StatelessFormula
import org.junit.Test

class CountingInspectorTest {

@Test
fun `assertEvaluationCount throws exception when count does not match`() {
val inspector = CountingInspector()
inspector.assertEvaluationCount(0)

val result = runCatching { inspector.assertEvaluationCount(5) }
Truth.assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"Evaluation count does not match - count: 0, expected: 5"
)
}

@Test
fun `assertEvaluationCount with types throws exception when count does not match`() {
val inspector = CountingInspector()
inspector.assertEvaluationCount(MyFormula::class, 0)
inspector.onEvaluateFinished(MyFormula::class, null, true)
inspector.assertEvaluationCount(MyFormula::class, 1)

val result = runCatching { inspector.assertEvaluationCount(MyFormula::class, 5) }
Truth.assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"Evaluation count does not match - count: 1, expected: 5"
)
}

@Test
fun `assertRunCount throws exception when count does not match`() {
val inspector = CountingInspector()
inspector.assertRunCount(0)

val result = runCatching { inspector.assertRunCount(5) }
Truth.assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"Run count does not match - count: 0, expected: 5"
)
}

@Test
fun `assertActionsStarted throws exception when count does not match`() {
val inspector = CountingInspector()
inspector.assertActionsStarted(0)

val result = runCatching { inspector.assertActionsStarted(5) }
Truth.assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"Actions started count does not match - count: 0, expected: 5"
)
}

@Test
fun `assertStateTransitions throws exception when count does not match`() {
val inspector = CountingInspector()
inspector.assertStateTransitions(MyFormula::class, 0)
inspector.onStateChanged(MyFormula::class, null, null, null)
inspector.assertStateTransitions(MyFormula::class, 1)

val result = runCatching { inspector.assertStateTransitions(MyFormula::class, 5) }
Truth.assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"State transition count does not match - count: 1, expected: 5"
)
}

class MyFormula : StatelessFormula<Unit, Unit>() {
override fun Snapshot<Unit, Unit>.evaluate(): Evaluation<Unit> {
return Evaluation(Unit)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.instacart.formula.test

import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import com.instacart.formula.Action
import com.instacart.formula.Cancelable
import org.junit.Test
import java.lang.IllegalStateException

class TestActionObserverTest {

@Test fun `assert values success`() {
multipleValueStream().test().assertValues(1, 2)
}

@Test fun `assert value fails due to different size`() {
val result = runCatching { multipleValueStream().test().assertValues(1) }
assertThat(result.exceptionOrNull()).isInstanceOf(AssertionError::class.java)
}

@Test fun `assert value fails due to different value`() {
val result = runCatching { multipleValueStream().test().assertValues(1, 5) }
assertThat(result.exceptionOrNull()).isInstanceOf(AssertionError::class.java)
}

@Test fun values() {
val values = multipleValueStream().test().values()
assertThat(values).hasSize(2)
}

@Test fun `cancel throws exception if action does not provide cancelable`() {
val result = kotlin.runCatching { multipleValueStream().test().cancel() }
assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"Action did not return a cancelable."
)
}

@Test fun `cancel invokes cancelable`() {
var cancelableCalled = 0
val action = object : Action<String> {
override fun start(send: (String) -> Unit): Cancelable {
return Cancelable { cancelableCalled += 1 }
}

override fun key(): Any? = null
}

action.test().cancel()
assertThat(cancelableCalled).isEqualTo(1)
}

private fun multipleValueStream() = object : Action<Int> {
override fun start(send: (Int) -> Unit): Cancelable? {
send(1)
send(2)
return null
}

override fun key(): Any = Unit
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.instacart.formula.test

import com.google.common.truth.Truth
import org.junit.Test

class TestCallbackTest {

@Test
fun `assertTimesCalled throws an exception when count does not match`() {
val callback = TestCallback()
callback.assertTimesCalled(0)
callback.invoke()
callback.assertTimesCalled(1)

val result = kotlin.runCatching { callback.assertTimesCalled(5) }
Truth.assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"Expected: 5, was: 1"
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.instacart.formula.test

import com.google.common.truth.Truth
import com.instacart.formula.Evaluation
import com.instacart.formula.Snapshot
import com.instacart.formula.StatelessFormula
import org.junit.Test

class TestFormulaObserverTest {

@Test fun `assertOutput passes if count matches`() {
val formula = object : StatelessFormula<Int, Int>() {
override fun Snapshot<Int, Unit>.evaluate(): Evaluation<Int> {
return Evaluation(input)
}
}

val observer = formula.test()
observer.input(1)
observer.assertOutputCount(1)

observer.input(10)
observer.assertOutputCount(2)
}

@Test fun `assertOutput throws exception if count does not match`() {
val formula = object : StatelessFormula<Int, Int>() {
override fun Snapshot<Int, Unit>.evaluate(): Evaluation<Int> {
return Evaluation(input)
}
}

val observer = formula.test()
observer.input(1)
val result = kotlin.runCatching {
observer.assertOutputCount(5)
}

Truth.assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"Expected: 5, was: 1"
)
}

@Test fun `output throws error if formula is not running`() {
val formula = object : StatelessFormula<Int, Int>() {
override fun Snapshot<Int, Unit>.evaluate(): Evaluation<Int> {
return Evaluation(input)
}
}

val result = runCatching {
formula.test().output { }
}
Truth.assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"Formula is not running. Call [TestFormulaObserver.input] to start it."
)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.instacart.formula.test

import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.fail
import org.junit.Test
Expand All @@ -9,8 +8,24 @@ class TestFormulaTest {
@Test fun `assert running count is zero when formula is not running`() {
val formula = TestSimpleFormula()
formula.implementation.assertRunningCount(0)
formula.test().input(SimpleFormula.Input())

val observer = formula.test()
observer.input(SimpleFormula.Input())
formula.implementation.assertRunningCount(1)

observer.dispose()
formula.implementation.assertRunningCount(0)
}

@Test
fun `assert running count throws an exception when count does not match`() {
val formula = TestSimpleFormula()
val result = runCatching {
formula.implementation.assertRunningCount(5)
}
assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"Expected 5 running formulas, but there were 0 instead"
)
}

@Test fun `emits initial output when subscribed`() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.instacart.formula.test

import com.google.common.truth.Truth
import org.junit.Test

class TestListenerTest {

@Test
fun `assertTimesCalled throws an exception when count does not match`() {
val listener = TestListener<String>()
listener.assertTimesCalled(0)
listener.invoke("value")
listener.assertTimesCalled(1)
listener.invoke("second")
listener.assertTimesCalled(2)

val result = runCatching { listener.assertTimesCalled(5) }
Truth.assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"Expected: 5, was: 2"
)
}

@Test
fun values() {
val listener = TestListener<String>()
listener.invoke("value")
listener.invoke("second")
listener.invoke("third")

Truth.assertThat(listener.values()).containsExactly(
"value", "second", "third"
).inOrder()
}
}
Loading

0 comments on commit 45666a3

Please sign in to comment.