We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
I find cases when Entry/Exit callback not called in Child state.
I try it in latest version 0.9.0 Below is unit test how to reproduce it
package ru.nsk.kstatemachine import io.kotest.core.spec.style.StringSpec class AdvancedCrossLevelTransitionTest : StringSpec({ "1. child to neighbors 1. child and then back 1. child" { val callbacks = mockkCallbacks() lateinit var state1: State lateinit var state11: State lateinit var state12: State lateinit var state2: State lateinit var state21: State lateinit var state22: State val machine = createStateMachine { state1 = initialState("1") { callbacks.listen(this) state11 = initialState("11") { callbacks.listen(this) transitionOn<SwitchEvent> { targetState = { state12 } callbacks.listen(this) } } state12 = state("12") { callbacks.listen(this) transitionOn<SwitchEvent> { targetState = { state11 } callbacks.listen(this) } } transitionOn<SwitchEventL1> { targetState = { state2 } callbacks.listen(this) } } state2 = state("2") { callbacks.listen(this) state21 = initialState("21") { callbacks.listen(this) transitionOn<SwitchEvent> { targetState = { state22 } callbacks.listen(this) } } state22 = state("22") { callbacks.listen(this) transitionOn<SwitchEvent> { targetState = { state21 } callbacks.listen(this) } } transitionOn<SwitchEventL1> { targetState = { state1 } callbacks.listen(this) } } } //* -> 1 (11) - ok verifySequenceAndClear(callbacks) { callbacks.onEntryState(state1) callbacks.onEntryState(state11) } //1 (11) -> 1 (12) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state11) callbacks.onEntryState(state12) } //1 (12) -> 2 (21) - ok machine.processEvent(SwitchEventL1) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEventL1) callbacks.onExitState(state12) callbacks.onExitState(state1) callbacks.onEntryState(state2) callbacks.onEntryState(state21) } //2 (21) -> 2 (22) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state21) callbacks.onEntryState(state22) } //2 (22) -> 1 (11) - ok machine.processEvent(SwitchEventL1) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEventL1) callbacks.onExitState(state22) callbacks.onExitState(state2) callbacks.onEntryState(state1) callbacks.onEntryState(state11) } //1 (11) -> 1 (12) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state11) callbacks.onEntryState(state12) } //1 (12) -> 1 (11) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state12) callbacks.onEntryState(state11) } //1 (11) -> 2 (21) - ok machine.processEvent(SwitchEventL1) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEventL1) callbacks.onExitState(state11) callbacks.onExitState(state1) callbacks.onEntryState(state2) callbacks.onEntryState(state21) } //2 (21) -> 1 (11) - failed (missing child entry callback) machine.processEvent(SwitchEventL1) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEventL1) callbacks.onExitState(state21) callbacks.onExitState(state2) callbacks.onEntryState(state1) callbacks.onEntryState(state11)//Missing entry state! } //1 (11) -> 1 (12) - failed (missing child exit callback) machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state11)//Missing exit state! callbacks.onEntryState(state12) } //1 (12) -> 1 (11) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state12) callbacks.onEntryState(state11) } //1 (11) -> 2 (21) - failed (missing child entry callback) machine.processEvent(SwitchEventL1) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEventL1) callbacks.onExitState(state11) callbacks.onExitState(state1) callbacks.onEntryState(state2) callbacks.onEntryState(state21)//Missing entry state! } } })
Solution how to fix it (with very ugly fix in State)
package ru.nsk.kstatemachine import io.kotest.core.spec.style.StringSpec import timber.log.Timber import kotlin.reflect.KMutableProperty1 import kotlin.reflect.full.memberProperties import kotlin.reflect.jvm.isAccessible open class FixedState( name: String? = null, childMode: ChildMode = ChildMode.EXCLUSIVE ) : DefaultState(name, childMode) { override fun onDoExit(transitionParams: TransitionParams<*>) { super.onDoExit(transitionParams) //Need clear CurrentState after exit // - not working - reEnter parent state after leaving it with child state (as initial state) try { DefaultStateWithDetail.propertyCurrentState?.set(this, null) } catch (e : Exception) { Timber.e(e, "Cannot set value for currentState property!") } } companion object { internal var propertyCurrentState : KMutableProperty1<InternalState, Any?>? = null init { try { propertyCurrentState = BaseStateImpl::class.memberProperties .find { it.name == "currentState" } ?.apply { isAccessible = true } as KMutableProperty1<InternalState, Any?> } catch (e : Exception){ Timber.e(e, "Cannot get currentState property!") } } } } class FixedAdvancedCrossLevelTransitionTest : StringSpec({ "1. child to neighbors 1. child and then back 1. child" { val callbacks = mockkCallbacks() val state1 = FixedState("1") val state11 = FixedState("11") val state12 = FixedState("12") val state2 = FixedState("2") val state21 = FixedState("21") val state22 = FixedState("22") val machine = createStateMachine { addInitialState(state1) { callbacks.listen(this) addInitialState(state11) { callbacks.listen(this) transitionOn<SwitchEvent> { targetState = { state12 } callbacks.listen(this) } } addState(state12) { callbacks.listen(this) transitionOn<SwitchEvent> { targetState = { state11 } callbacks.listen(this) } } transitionOn<SwitchEventL1> { targetState = { state2 } callbacks.listen(this) } } addState(state2) { callbacks.listen(this) addInitialState(state21) { callbacks.listen(this) transitionOn<SwitchEvent> { targetState = { state22 } callbacks.listen(this) } } addState(state22) { callbacks.listen(this) transitionOn<SwitchEvent> { targetState = { state21 } callbacks.listen(this) } } transitionOn<SwitchEventL1> { targetState = { state1 } callbacks.listen(this) } } } //* -> 1 (11) - ok verifySequenceAndClear(callbacks) { callbacks.onEntryState(state1) callbacks.onEntryState(state11) } //1 (11) -> 1 (12) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state11) callbacks.onEntryState(state12) } //1 (12) -> 2 (21) - ok machine.processEvent(SwitchEventL1) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEventL1) callbacks.onExitState(state12) callbacks.onExitState(state1) callbacks.onEntryState(state2) callbacks.onEntryState(state21) } //2 (21) -> 2 (22) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state21) callbacks.onEntryState(state22) } //2 (22) -> 1 (11) - ok machine.processEvent(SwitchEventL1) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEventL1) callbacks.onExitState(state22) callbacks.onExitState(state2) callbacks.onEntryState(state1) callbacks.onEntryState(state11) } //1 (11) -> 1 (12) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state11) callbacks.onEntryState(state12) } //1 (12) -> 1 (11) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state12) callbacks.onEntryState(state11) } //1 (11) -> 2 (21) - ok machine.processEvent(SwitchEventL1) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEventL1) callbacks.onExitState(state11) callbacks.onExitState(state1) callbacks.onEntryState(state2) callbacks.onEntryState(state21) } //2 (21) -> 1 (11) - ok machine.processEvent(SwitchEventL1) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEventL1) callbacks.onExitState(state21) callbacks.onExitState(state2) callbacks.onEntryState(state1) callbacks.onEntryState(state11) } //1 (11) -> 1 (12) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state11) callbacks.onEntryState(state12) } //1 (12) -> 1 (11) - ok machine.processEvent(SwitchEvent) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEvent) callbacks.onExitState(state12) callbacks.onEntryState(state11) } //1 (11) -> 2 (21) - ok machine.processEvent(SwitchEventL1) verifySequenceAndClear(callbacks) { callbacks.onTriggeredTransition(SwitchEventL1) callbacks.onExitState(state11) callbacks.onExitState(state1) callbacks.onEntryState(state2) callbacks.onEntryState(state21) } } })
The text was updated successfully, but these errors were encountered:
Thank you, I will check it out after 16'th February.
Sorry, something went wrong.
I confirm a bug, and start working on a fix. Thank you for a good test sample.
Fixed by clearing currentState field on exiting state.
8f658cf
nsk90
No branches or pull requests
I find cases when Entry/Exit callback not called in Child state.
I try it in latest version 0.9.0
Below is unit test how to reproduce it
Solution how to fix it (with very ugly fix in State)
The text was updated successfully, but these errors were encountered: