package usecase import ( "strings" "testing" ) func TestValidateCandidateHumanReviewAcceptsStructuredSelection(t *testing.T) { selected := 2 command := validCandidateHumanReviewCommand() command.SelectedCandidateOrdinal = &selected command.Items = []CandidateHumanReviewItemInput{ { CandidateOrdinal: 1, Label: "REJECT", PrimaryReasonCode: "NOT_BEST_MATCH", ReasonCodes: []string{"NOT_BEST_MATCH"}, }, { CandidateOrdinal: 2, Label: "ACCEPT", PrimaryReasonCode: "SKU_MATCH", ReasonCodes: []string{"SKU_MATCH", "IMAGE_MATCH"}, }, } if err := validateCandidateHumanReview(command); err != nil { t.Fatalf("validate structured selection: %v", err) } } func TestValidateCandidateHumanReviewRejectsMissingSelectedItem(t *testing.T) { selected := 2 command := validCandidateHumanReviewCommand() command.SelectedCandidateOrdinal = &selected if err := validateCandidateHumanReview(command); err == nil { t.Fatal("expected missing selected item to be rejected") } } func TestValidateCandidateHumanReviewRequiresOtherNote(t *testing.T) { command := validCandidateHumanReviewCommand() command.PrimaryReasonCode = "OTHER" command.Note = "短" if err := validateCandidateHumanReview(command); err == nil { t.Fatal("expected short OTHER note to be rejected") } command.Note = "人工判断更合适" if err := validateCandidateHumanReview(command); err != nil { t.Fatalf("validate OTHER note: %v", err) } } func TestValidateCandidateHumanReviewAllowsEmptyNoMatch(t *testing.T) { command := validCandidateHumanReviewCommand() command.Outcome = "NO_MATCH" command.SelectedCandidateOrdinal = nil command.PrimaryReasonCode = "NO_ACCEPTABLE_CANDIDATE" command.Items = nil if err := validateCandidateHumanReview(command); err != nil { t.Fatalf("validate empty no-match review: %v", err) } } func validCandidateHumanReviewCommand() StoreCandidateHumanReviewCommand { selected := 1 return StoreCandidateHumanReviewCommand{ TaskContentSHA256: strings.Repeat("a", 64), ReasonSchemaVersion: 1, Outcome: "CANDIDATE_ACCEPTED", SelectedCandidateOrdinal: &selected, PrimaryReasonCode: "SELECTED_BEST_MATCH", Items: []CandidateHumanReviewItemInput{ { CandidateOrdinal: 1, Label: "ACCEPT", PrimaryReasonCode: "SKU_MATCH", ReasonCodes: []string{"SKU_MATCH"}, }, }, } }