package state import "testing" func TestValidTransitions(t *testing.T) { m := NewMachine(ConversationSession{CallID: "c"}) steps := []ConversationEvent{ {Type: EventCallStarted}, {Type: EventGreetingPlayed}, {Type: EventLanguageSelected, Language: LanguageRU}, {Type: EventRegionSelected, Region: RegionSelection{Code: "almaty_city", Status: RegionSelected}}, {Type: EventQuestionReceived, Question: "q"}, {Type: EventAnswerCompleted}, {Type: EventHandoffRequested}, {Type: EventCallEnded}, } want := []ConversationState{StateGreeting, StateReadyToHelp, StateReadyToHelp, StateReadyToHelp, StateQuestionAnswering, StateReadyToHelp, StateHandoff, StateEnded} for i, step := range steps { res, err := m.Apply(step) if err != nil { t.Fatalf("step %d: %v", i, err) } if res.To != want[i] { t.Fatalf("step %d state=%s want=%s", i, res.To, want[i]) } } if len(m.Session().TransitionHistory) != len(steps) { t.Fatalf("transition history length mismatch") } } func TestInvalidTransitionsDoNotMutate(t *testing.T) { m := NewMachine(ConversationSession{CallID: "c"}) if _, err := m.Apply(ConversationEvent{Type: EventQuestionReceived}); err == nil { t.Fatal("expected invalid transition") } if m.CurrentState() != StateCallStarted { t.Fatalf("state mutated to %s", m.CurrentState()) } _, _ = m.Apply(ConversationEvent{Type: EventCallEnded}) if _, err := m.Apply(ConversationEvent{Type: EventLanguageSelected, Language: LanguageRU}); err == nil { t.Fatal("expected ended state error") } if m.CurrentState() != StateEnded { t.Fatalf("ended state mutated to %s", m.CurrentState()) } } func TestQuestionAllowedWithoutExplicitLanguageAndRegion(t *testing.T) { m := NewMachine(ConversationSession{CallID: "c", State: StateRegionSelection, Language: LanguageRU}) if _, err := m.Apply(ConversationEvent{Type: EventQuestionReceived}); err == nil { t.Fatal("region selection state should not answer directly") } m = NewMachine(ConversationSession{CallID: "c", State: StateReadyToHelp, Region: RegionSelection{Code: "almaty_city", Status: RegionSelected}}) if _, err := m.Apply(ConversationEvent{Type: EventQuestionReceived}); err == nil { return } t.Fatal("question should be allowed without explicit language") }