package domain_test import ( "errors" "testing" "cmbuyer/admin/internal/domain" ) func TestTaskTransitions(t *testing.T) { tests := []struct { name string current domain.TaskStatus next domain.TaskStatus allowed bool }{ {"start purchase", domain.TaskStatusDraft, domain.TaskStatusPending, true}, {"cancel draft before fence", domain.TaskStatusDraft, domain.TaskStatusCanceled, true}, {"claim purchase", domain.TaskStatusPending, domain.TaskStatusClaimed, true}, {"release expired authorization", domain.TaskStatusPending, domain.TaskStatusDraft, true}, {"start ordering", domain.TaskStatusClaimed, domain.TaskStatusOrdering, true}, {"release unstarted claim", domain.TaskStatusClaimed, domain.TaskStatusDraft, true}, {"ordering needs manual review", domain.TaskStatusOrdering, domain.TaskStatusNeedsManual, true}, {"order reaches payment", domain.TaskStatusOrdering, domain.TaskStatusWaitingPayment, true}, {"order needs manual review before fence", domain.TaskStatusOrdering, domain.TaskStatusNeedsManual, true}, {"order needs reconciliation", domain.TaskStatusOrdering, domain.TaskStatusReconciliationRequired, true}, {"manual review resets draft", domain.TaskStatusNeedsManual, domain.TaskStatusDraft, true}, {"manual review cancels before fence", domain.TaskStatusNeedsManual, domain.TaskStatusCanceled, true}, {"payment verified", domain.TaskStatusWaitingPayment, domain.TaskStatusSucceeded, true}, {"reconcile confirms waiting payment", domain.TaskStatusReconciliationRequired, domain.TaskStatusWaitingPayment, true}, {"reconcile confirms failed", domain.TaskStatusReconciliationRequired, domain.TaskStatusFailed, true}, {"cannot skip authorization", domain.TaskStatusDraft, domain.TaskStatusOrdering, false}, {"ordering cannot return pending", domain.TaskStatusOrdering, domain.TaskStatusPending, false}, {"ordering cannot bypass manual review to draft", domain.TaskStatusOrdering, domain.TaskStatusDraft, false}, {"terminal task cannot restart", domain.TaskStatusSucceeded, domain.TaskStatusPending, false}, {"unknown status is rejected", domain.TaskStatus("UNKNOWN"), domain.TaskStatusPending, false}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { if got := test.current.CanTransitionTo(test.next); got != test.allowed { t.Fatalf("CanTransitionTo(%s, %s) = %t, want %t", test.current, test.next, got, test.allowed) } result, err := domain.TransitionTask(test.current, test.next) if test.allowed { if err != nil { t.Fatalf("TransitionTask(%s, %s): %v", test.current, test.next, err) } if result != test.next { t.Fatalf("TransitionTask(%s, %s) = %s, want %s", test.current, test.next, result, test.next) } return } if !errors.Is(err, domain.ErrInvalidTaskTransition) { t.Fatalf("TransitionTask(%s, %s) error = %v, want ErrInvalidTaskTransition", test.current, test.next, err) } if result != test.current { t.Fatalf("TransitionTask(%s, %s) result = %s, want unchanged status", test.current, test.next, result) } }) } }