package emotion import "testing" func TestDefaultTransitions_StandardEdges(t *testing.T) { t.Parallel() d := DefaultTransitions() if _, ok := d[Calm]; !ok { t.Errorf("DefaultTransitions missing %q", Calm) } if _, ok := d[Angry]; !ok { t.Errorf("DefaultTransitions missing %q", Angry) } } func TestNewMachine_DefaultTransitionsWhenEmpty(t *testing.T) { t.Parallel() m, err := NewMachine(Params{InitialState: Excited}) if err != nil { t.Fatalf("NewMachine() error: %v", err) } if got := m.Current(); got != Excited { t.Fatalf("Current() = %q, want %q", got, Excited) } if !m.CanTransition(Happy) { t.Errorf("excited should be able to reach happy by default") } if m.CanTransition(Sad) { t.Errorf("excited must not reach sad by default") } } func TestNewMachine_RejectsNegativeDecay(t *testing.T) { t.Parallel() if _, err := NewMachine(Params{InitialState: Calm, DecayRate: -1}); err == nil { t.Fatal("NewMachine() should error on negative decay rate") } } func TestMachine_TransitionFollowsTable(t *testing.T) { t.Parallel() tr := map[EmotionState][]EmotionState{ Calm: {Happy, Sad, Excited}, Happy: {Excited, Calm}, Sad: {Calm}, Angry: {Calm}, } tests := []struct { name string initial EmotionState to EmotionState wantErr bool }{ {name: "ok_calm_to_happy", initial: Calm, to: Happy}, {name: "ok_calm_to_excited", initial: Calm, to: Excited}, {name: "ok_happy_to_excited", initial: Happy, to: Excited}, {name: "reject_calm_to_angry", initial: Calm, to: Angry, wantErr: true}, {name: "reject_happy_to_sad", initial: Happy, to: Sad, wantErr: true}, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() m, err := NewMachine(Params{InitialState: tt.initial, Transitions: tr}) if err != nil { t.Fatalf("NewMachine() error: %v", err) } err = m.Transition(tt.to) if tt.wantErr && err == nil { t.Fatalf("Transition(%q) want error, got nil", tt.to) } if !tt.wantErr && err != nil { t.Fatalf("Transition(%q) want nil, got %v", tt.to, err) } if !tt.wantErr && m.Current() != tt.to { t.Fatalf("Current() = %q, want %q", m.Current(), tt.to) } }) } } func TestMachine_SetForce(t *testing.T) { t.Parallel() m, err := NewMachine(Params{InitialState: Calm}) if err != nil { t.Fatalf("NewMachine() error: %v", err) } m.Set(Angry) if got := m.Current(); got != Angry { t.Fatalf("Current() = %q, want %q", got, Angry) } } func TestMachine_AddTransitionExtends(t *testing.T) { t.Parallel() tr := map[EmotionState][]EmotionState{Calm: {Happy}} m, err := NewMachine(Params{InitialState: Calm, Transitions: tr}) if err != nil { t.Fatalf("NewMachine() error: %v", err) } if m.CanTransition(Angry) { t.Fatalf("calm must not reach angry before AddTransition") } m.AddTransition(Calm, Angry) if !m.CanTransition(Angry) { t.Errorf("calm should reach angry after AddTransition") } } func TestMachine_DecayMovesTowardCalm(t *testing.T) { t.Parallel() m, err := NewMachine(Params{InitialState: Excited, DecayRate: 1}) if err != nil { t.Fatalf("NewMachine() error: %v", err) } if got := m.Decay(); got != Happy { t.Fatalf("Decay() from excited = %q, want %q", got, Happy) } if got := m.Decay(); got != Calm { t.Fatalf("Decay() from happy = %q, want %q", got, Calm) } if got := m.Decay(); got != Calm { t.Fatalf("Decay() from calm = %q, want %q", got, Calm) } } func TestMachine_DecayDisabledAtZeroRate(t *testing.T) { t.Parallel() m, err := NewMachine(Params{InitialState: Angry, DecayRate: 0}) if err != nil { t.Fatalf("NewMachine() error: %v", err) } if got := m.Decay(); got != Angry { t.Fatalf("Decay() at zero rate = %q, want %q", got, Angry) } }