Files
Assistant/modules/continuity/domain/human_response_test.go
m 8b9b841645
CI / test (push) Successful in 21s
CI / test (pull_request) Successful in 16s
DEV-000066 human response continuation semantics
2026-08-17 17:02:33 +03:00

87 lines
3.9 KiB
Go

package domain
import (
"strings"
"testing"
"time"
"git.cin.su/m/Assistant/contracts/authority"
"git.cin.su/m/Assistant/contracts/continuity"
"git.cin.su/m/Assistant/contracts/identity"
)
func TestInterpretHumanResponseCompletesSingleDeliveredReminder(t *testing.T) {
result := interpretResponseForTest(t, "Готово", []ResponseCandidate{responseCandidate("a1", "p1", "позвонить врачу")})
if !result.Handled || result.Response.Operation != continuity.ResponseComplete || result.Response.Outcome != continuity.ResponseOutcomeUserReportedComplete || !result.Response.UserReportedNotVerified {
t.Fatalf("unexpected complete response: %#v", result)
}
}
func TestInterpretHumanResponseSnoozesSingleReminder(t *testing.T) {
result := interpretResponseForTest(t, "Отложи на 10 минут", []ResponseCandidate{responseCandidate("a1", "p1", "проверить базу")})
if !result.Handled || result.Response.Operation != continuity.ResponseSnooze || result.Response.Outcome != continuity.ResponseOutcomeSnoozed {
t.Fatalf("unexpected snooze response: %#v", result)
}
if result.Response.SnoozeUntilUnixMillis != time.Unix(100, 0).Add(10*time.Minute).UnixMilli() {
t.Fatalf("unexpected snooze time: %d", result.Response.SnoozeUntilUnixMillis)
}
}
func TestInterpretHumanResponseCancelsSingleReminder(t *testing.T) {
result := interpretResponseForTest(t, "Отмени", []ResponseCandidate{responseCandidate("a1", "p1", "встретить курьера")})
if !result.Handled || result.Response.Operation != continuity.ResponseCancel || result.Response.Outcome != continuity.ResponseOutcomeCancelled {
t.Fatalf("unexpected cancel response: %#v", result)
}
}
func TestInterpretHumanResponseAmbiguousTargetAsksClarificationWithoutResolvedMutation(t *testing.T) {
result := interpretResponseForTest(t, "Готово", []ResponseCandidate{responseCandidate("a1", "p1", "первое"), responseCandidate("a2", "p2", "второе")})
if !result.Handled || result.Response.ResolutionState != continuity.ResponseAmbiguous || result.Response.Outcome != continuity.ResponseOutcomeClarificationNeeded || !strings.Contains(result.Reply, "несколько") {
t.Fatalf("expected ambiguity clarification, got %#v", result)
}
}
func TestInterpretHumanResponseNoTargetAsksClarification(t *testing.T) {
result := interpretResponseForTest(t, "Готово", nil)
if !result.Handled || result.Response.ResolutionState != continuity.ResponseNoTarget || result.Response.Outcome != continuity.ResponseOutcomeClarificationNeeded {
t.Fatalf("expected no-target clarification, got %#v", result)
}
}
func interpretResponseForTest(t *testing.T, message string, candidates []ResponseCandidate) continuity.HumanResponseResult {
t.Helper()
result, err := InterpretHumanResponse(continuity.HumanResponseRequest{
SourceUtteranceID: "utterance-1",
SourceIntentID: "intent-1",
Message: message,
RequestedAtUnixMillis: time.Unix(100, 0).UnixMilli(),
}, identity.PrincipalID("principal-1"), authority.ScopeID("scope-1"), continuity.HumanResponseID("response-1"), candidates, time.Unix(100, 0))
if err != nil {
t.Fatal(err)
}
return result
}
func responseCandidate(attentionID continuity.AttentionItemID, prospectiveID continuity.ProspectiveItemID, summary string) ResponseCandidate {
return ResponseCandidate{
Attention: continuity.AttentionItem{
ID: attentionID,
OwnerPrincipalID: "principal-1",
ScopeID: "scope-1",
SourceKind: continuity.AttentionSourceProspectiveReminder,
SourceProspectiveID: prospectiveID,
State: continuity.AttentionDelivered,
Summary: summary,
Revision: 1,
},
Prospective: continuity.ProspectiveItem{
ID: prospectiveID,
OwnerPrincipalID: "principal-1",
ScopeID: "scope-1",
Summary: summary,
State: continuity.ProspectiveDelivered,
Revision: 1,
},
}
}