Skip to content

Commit

Permalink
Miscellaneous coverage improvements.
Browse files Browse the repository at this point in the history
  • Loading branch information
Laimiux committed Mar 15, 2024
1 parent 17718e5 commit 673c99d
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 41 deletions.
12 changes: 1 addition & 11 deletions formula/src/main/java/com/instacart/formula/Cancelable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,6 @@ package com.instacart.formula
/**
* Used within [Action] to receive a cancel event and perform clean up.
*/
interface Cancelable {
companion object {
inline operator fun invoke(crossinline cancel: () -> Unit): Cancelable {
return object : Cancelable {
override fun cancel() {
cancel()
}
}
}
}

fun interface Cancelable {
fun cancel()
}
21 changes: 7 additions & 14 deletions formula/src/main/java/com/instacart/formula/DeferredAction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ package com.instacart.formula
*/
class DeferredAction<Event>(
val key: Any,
val action: Action<Event>,
private val action: Action<Event>,
// We use event listener for equality because it provides better equality performance
val initial: (Event) -> Unit
private val initial: (Event) -> Unit
) {
private var cancelable: Cancelable? = null

internal var listener: (Event) -> Unit = initial
internal var cancelable: Cancelable? = null

internal fun start() {
cancelable = action.start() { message ->
Expand All @@ -24,22 +24,15 @@ class DeferredAction<Event>(
cancelable = null
}

/**
* Action equality is based on the [initial] listener.
*/
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as DeferredAction<*>

if (initial != other.initial) return false

return true
return other is DeferredAction<*> && initial == other.initial
}

override fun hashCode(): Int {
return initial.hashCode()
}

fun keyAsString(): String {
return key.toString()
}
}
4 changes: 2 additions & 2 deletions formula/src/main/java/com/instacart/formula/FormulaContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,12 @@ abstract class FormulaContext<out Input, State> internal constructor(
internal abstract fun <Event> eventListener(
key: Any,
useIndex: Boolean = true,
executionType: Transition.ExecutionType? = null,
executionType: Transition.ExecutionType?,
transition: Transition<Input, State, Event>
): Listener<Event>

// Internal key scope management
@PublishedApi internal abstract fun enterScope(key: Any)
@PublishedApi internal abstract fun endScope()
@PublishedApi internal abstract fun createScopedKey(type: KClass<*>, key: Any? = null): Any
@PublishedApi internal abstract fun createScopedKey(type: KClass<*>, key: Any?): Any
}
31 changes: 31 additions & 0 deletions formula/src/test/java/com/instacart/formula/DeferredActionTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.instacart.formula

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

class DeferredActionTest {

@Test
fun `identity equality returns true`() {
val callback = { _: Unit -> }
val action = DeferredAction(key = "1", action = Action.onInit(), callback)
assertThat(action.equals(action)).isTrue()
}

@Test
fun `when class is different, equality returns false`() {
val callback = { _: Unit -> }
val action = DeferredAction(key = "1", action = Action.onInit(), callback)
assertThat(action).isNotEqualTo("string")
}

@Test
fun `when listeners are not equal, the actions are not equal`() {
val callback = { _: Unit -> }
val callback2 = { _: Unit -> }
val action1 = DeferredAction(key = "1", action = Action.onInit(), callback)
val action2 = DeferredAction(key = "1", action = Action.onInit(), callback2)

assertThat(action1).isNotEqualTo(action2)
}
}
43 changes: 29 additions & 14 deletions formula/src/test/java/com/instacart/formula/TransitionApiTest.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.instacart.formula

import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import com.instacart.formula.internal.DelegateTransitionContext
import com.instacart.formula.internal.toResult
import com.instacart.formula.test.TestListener
Expand All @@ -11,18 +12,32 @@ class TransitionApiTest {
@Test fun `none transition`() {
val transition = Transition<Unit, Int, Unit> { none() }
val result = transition.toResult(DelegateTransitionContext(Unit, 0), Unit)
Truth.assertThat(result).isEqualTo(Transition.Result.None)
assertThat(result).isEqualTo(Transition.Result.None)
}

@Test fun `none transition has no effects`() {
val result = Transition.Result.None
Truth.assertThat(result.effects).isEmpty()
assertThat(result.effects).isEmpty()
}

@Test fun `state transition result with effect type but null effect`() {
val result = DelegateTransitionContext(Unit, 0)
.transition(1, Effect.Unconfined, null)

assertThat(result.state).isEqualTo(1)
assertThat(result.effects).isEmpty()
}

@Test fun `transition returns null if effect is null`() {
val result = DelegateTransitionContext(Unit, 0)
.transition(Effect.Unconfined, null)
assertThat(result).isEqualTo(Transition.Result.None)
}

@Test fun `stateful transition`() {
val transition = Transition<Unit, Int, Unit> { transition(state + 1) }
val result = transition.toResult(DelegateTransitionContext(Unit, 0), Unit).assertStateful()
Truth.assertThat(result.state).isEqualTo(1)
assertThat(result.state).isEqualTo(1)
}

@Test fun `stateful transition with effects`() {
Expand All @@ -34,7 +49,7 @@ class TransitionApiTest {
}

val result = transition.toResult(DelegateTransitionContext(Unit, 0), Unit).assertStateful()
Truth.assertThat(result.state).isEqualTo(1)
assertThat(result.state).isEqualTo(1)

result.assertAndExecuteEffects()
testListener.assertTimesCalled(1)
Expand All @@ -59,7 +74,7 @@ class TransitionApiTest {
delegate(AddTransition(), 5)
}
val result = transition.toResult(DelegateTransitionContext(Unit, 0), Unit).assertStateful()
Truth.assertThat(result.state).isEqualTo(5)
assertThat(result.state).isEqualTo(5)
}

@Test fun `transition combine none transition with stateful transition`() {
Expand All @@ -68,7 +83,7 @@ class TransitionApiTest {
}

val result = transition.toResult(DelegateTransitionContext(Unit, 0), Unit).assertStateful()
Truth.assertThat(result.state).isEqualTo(1)
assertThat(result.state).isEqualTo(1)
}

@Test fun `transition combine only effects transition with stateful transition`() {
Expand All @@ -79,7 +94,7 @@ class TransitionApiTest {
}

val result = transition.toResult(DelegateTransitionContext(Unit, 0), Unit).assertStateful()
Truth.assertThat(result.state).isEqualTo(1)
assertThat(result.state).isEqualTo(1)

result.assertAndExecuteEffects()
testListener.assertTimesCalled(1)
Expand All @@ -91,7 +106,7 @@ class TransitionApiTest {
}

val result = transition.toResult(DelegateTransitionContext(Unit, 0), Unit).assertStateful()
Truth.assertThat(result.state).isEqualTo(2)
assertThat(result.state).isEqualTo(2)
}

@Test fun `transition combine keeps effect order`() {
Expand All @@ -102,10 +117,10 @@ class TransitionApiTest {
}

val result = transition.toResult(DelegateTransitionContext(Unit, 0), Unit).assertStateful()
Truth.assertThat(result.state).isEqualTo(2)
assertThat(result.state).isEqualTo(2)

result.assertAndExecuteEffects()
Truth.assertThat(listener.values()).containsExactly(1, 2).inOrder()
assertThat(listener.values()).containsExactly(1, 2).inOrder()
}

@Test fun `state andThen another stateful result`() {
Expand All @@ -114,7 +129,7 @@ class TransitionApiTest {
}

val result = transition.toResult(DelegateTransitionContext(Unit, 0), Unit).assertStateful()
Truth.assertThat(result.state).isEqualTo(3)
assertThat(result.state).isEqualTo(3)
}

@Test fun `state andThen empty result`() {
Expand All @@ -124,16 +139,16 @@ class TransitionApiTest {
}

val result = transition.toResult(DelegateTransitionContext(Unit, 0), Unit).assertStateful()
Truth.assertThat(result.state).isEqualTo(1)
assertThat(result.state).isEqualTo(1)
}

private fun <State> Transition.Result<State>.assertStateful(): Transition.Result.Stateful<State> {
Truth.assertThat(this).isInstanceOf(Transition.Result.Stateful::class.java)
assertThat(this).isInstanceOf(Transition.Result.Stateful::class.java)
return this as Transition.Result.Stateful<State>
}

private fun <State> Transition.Result<State>.assertAndExecuteEffects() {
Truth.assertThat(effects).isNotEmpty()
assertThat(effects).isNotEmpty()
for (effect in effects) {
effect.executable()
}
Expand Down

0 comments on commit 673c99d

Please sign in to comment.