diff --git a/formula/src/test/java/com/instacart/formula/FormulaRuntimeTest.kt b/formula/src/test/java/com/instacart/formula/FormulaRuntimeTest.kt index 61e095fd..867980ee 100644 --- a/formula/src/test/java/com/instacart/formula/FormulaRuntimeTest.kt +++ b/formula/src/test/java/com/instacart/formula/FormulaRuntimeTest.kt @@ -1352,7 +1352,7 @@ class FormulaRuntimeTest(val runtime: TestableRuntime, val name: String) { } } - // TODO: I'm not sure if this is the right behaviro + // TODO: I'm not sure if this is the right behavior @Test fun `action termination events are ignored`() { val formula = object : Formula() { diff --git a/formula/src/test/java/com/instacart/formula/FormulaValidationTest.kt b/formula/src/test/java/com/instacart/formula/FormulaValidationTest.kt new file mode 100644 index 00000000..2790de09 --- /dev/null +++ b/formula/src/test/java/com/instacart/formula/FormulaValidationTest.kt @@ -0,0 +1,86 @@ +package com.instacart.formula + +import com.google.common.truth.Truth +import com.instacart.formula.test.test +import org.junit.Test +import java.util.concurrent.atomic.AtomicInteger + +class FormulaValidationTest { + + @Test + fun `input changed during re-evaluation will throw validation error`() { + val childFormula = object : StatelessFormula() { + override fun Snapshot.evaluate(): Evaluation { + return Evaluation(output = input) + } + } + + val parentFormula = object : StatelessFormula() { + val unstableInput = AtomicInteger(0) + override fun Snapshot.evaluate(): Evaluation { + return Evaluation( + output = context.child(childFormula, unstableInput.incrementAndGet()) + ) + } + } + + val error = runCatching { + parentFormula.test(isValidationEnabled = true).input(Unit) + } + + Truth.assertThat(error.exceptionOrNull()).hasMessageThat().contains( + "- input changed during identical re-evaluation - old: 1, new: 2" + ) + } + + @Test + fun `output changed during re-evaluation will throw validation error`() { + val formula = object : StatelessFormula() { + val unstableOutput = AtomicInteger(0) + override fun Snapshot.evaluate(): Evaluation { + return Evaluation( + output = unstableOutput.incrementAndGet() + ) + } + } + val error = runCatching { + formula.test(isValidationEnabled = true).input(Unit) + } + Truth.assertThat(error.exceptionOrNull()).hasMessageThat().contains( + "- output changed during identical re-evaluation - old: 1, new: 2" + ) + } + + @Test + fun `action key changed during re-evaluation will throw validation error`() { + val formula = object : StatelessFormula() { + val unstableActionKey = AtomicInteger(0) + override fun Snapshot.evaluate(): Evaluation { + return Evaluation( + output = 0, + context.actions { + val action = object : Action { + override fun start(send: (Unit) -> Unit): Cancelable? { + return null + } + + override fun key(): Any { + return unstableActionKey.incrementAndGet() + } + } + + action.onEvent { + none() + } + } + ) + } + } + val error = runCatching { + formula.test(isValidationEnabled = true).input(Unit) + } + Truth.assertThat(error.exceptionOrNull()).hasMessageThat().contains( + "action keys changed during identical re-evaluation" + ) + } +} \ No newline at end of file