Files
Cyrene_v2/internal/runtime/orchestration/audit/context_test.go
T

243 lines
6.7 KiB
Go

package audit
import (
"context"
"errors"
"testing"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
)
// texts builds a context of text-only messages with the given body texts.
func texts(role model.Role, bodies ...string) []model.Message {
out := make([]model.Message, 0, len(bodies))
for _, b := range bodies {
out = append(out, model.TextMessage(role, b))
}
return out
}
// sameMessage compares a message by role and concatenated text; the test
// messages are text-only, so this is sufficient for equality.
func sameMessage(a, b model.Message) bool {
return a.Role == b.Role && messageText(a) == messageText(b)
}
func TestNewContextAuditor_Snapshot(t *testing.T) {
t.Parallel()
msgs := texts(model.RoleUser, "alpha", "bravo", "charlie")
aud := NewContextAuditor(msgs)
// Mutating the caller's slice after construction must not affect the audit.
msgs[0].Role = model.RoleSystem
got := aud.Full()
if got[0].Role != model.RoleUser {
t.Fatalf("snapshot leaked caller mutation: role = %q, want %q", got[0].Role, model.RoleUser)
}
}
func TestFull_ReturnsDefensiveCopy(t *testing.T) {
t.Parallel()
aud := NewContextAuditor(texts(model.RoleUser, "alpha", "bravo"))
got := aud.Full()
got[0].Role = model.RoleSystem
got[1].Role = model.RoleSystem
fresh := aud.Full()
if fresh[0].Role != model.RoleUser || fresh[1].Role != model.RoleUser {
t.Fatalf("Full leaked mutation of its returned copy: %+v", fresh)
}
}
func TestTail(t *testing.T) {
t.Parallel()
full := texts(model.RoleUser, "alpha", "bravo", "charlie", "delta")
aud := NewContextAuditor(full)
tests := []struct {
name string
n int
want []string
}{
{name: "zero returns empty", n: 0, want: nil},
{name: "negative returns empty", n: -1, want: nil},
{name: "single", n: 1, want: []string{"delta"}},
{name: "pair", n: 2, want: []string{"charlie", "delta"}},
{name: "exact length", n: 4, want: []string{"alpha", "bravo", "charlie", "delta"}},
{name: "beyond length clamps to full", n: 9, want: []string{"alpha", "bravo", "charlie", "delta"}},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := aud.Tail(tt.n)
if len(got) != len(tt.want) {
t.Fatalf("Tail(%d) length = %d, want %d", tt.n, len(got), len(tt.want))
}
for i := range got {
if got[i].Role != model.RoleUser || messageText(got[i]) != tt.want[i] {
t.Fatalf("Tail(%d)[%d] = %q/%s, want text %q", tt.n, i, messageText(got[i]), got[i].Role, tt.want[i])
}
}
})
}
}
func TestKeyword_LocateWithSurroundings(t *testing.T) {
t.Parallel()
aud := NewContextAuditor(texts(model.RoleUser, "alpha", "bravo", "charlie"))
loc, err := aud.Keyword(context.Background(), "rav")
if err != nil {
t.Fatalf("Keyword unexpected error: %v", err)
}
if loc == nil {
t.Fatal("Keyword returned nil for a present match")
}
if loc.Line != 2 {
t.Fatalf("Line = %d, want 2", loc.Line)
}
if len(loc.Surrounding) != 3 {
t.Fatalf("Surrounding length = %d, want 3", len(loc.Surrounding))
}
if !sameMessage(loc.Surrounding[1], model.TextMessage(model.RoleUser, "bravo")) {
t.Fatalf("matched message missing from window: %+v", loc.Surrounding)
}
if !sameMessage(loc.Surrounding[0], model.TextMessage(model.RoleUser, "alpha")) {
t.Fatalf("above-message missing from window: %+v", loc.Surrounding)
}
if !sameMessage(loc.Surrounding[2], model.TextMessage(model.RoleUser, "charlie")) {
t.Fatalf("below-message missing from window: %+v", loc.Surrounding)
}
}
func TestKeyword_Edges(t *testing.T) {
t.Parallel()
t.Run("first message has no above-neighbor", func(t *testing.T) {
t.Parallel()
aud := NewContextAuditor(texts(model.RoleUser, "alpha", "bravo"))
loc, err := aud.Keyword(context.Background(), "alp")
if err != nil {
t.Fatalf("Keyword unexpected error: %v", err)
}
if loc.Line != 1 {
t.Fatalf("Line = %d, want 1", loc.Line)
}
if len(loc.Surrounding) != 2 {
t.Fatalf("Surrounding length = %d, want 2", len(loc.Surrounding))
}
})
t.Run("last message has no below-neighbor", func(t *testing.T) {
t.Parallel()
aud := NewContextAuditor(texts(model.RoleUser, "alpha", "bravo"))
loc, err := aud.Keyword(context.Background(), "bra")
if err != nil {
t.Fatalf("Keyword unexpected error: %v", err)
}
if loc.Line != 2 {
t.Fatalf("Line = %d, want 2", loc.Line)
}
if len(loc.Surrounding) != 2 {
t.Fatalf("Surrounding length = %d, want 2", len(loc.Surrounding))
}
})
}
func TestKeyword_CaseInsensitive(t *testing.T) {
t.Parallel()
aud := NewContextAuditor(texts(model.RoleUser, "alpha", "bravo"))
loc, err := aud.Keyword(context.Background(), "BRAVO")
if err != nil {
t.Fatalf("Keyword unexpected error: %v", err)
}
if loc == nil || loc.Line != 2 {
t.Fatalf("case-insensitive match failed: line = %d", loc.Line)
}
}
func TestKeyword_NoMatch(t *testing.T) {
t.Parallel()
aud := NewContextAuditor(texts(model.RoleUser, "alpha", "bravo"))
loc, err := aud.Keyword(context.Background(), "zzz")
if err != nil {
t.Fatalf("Keyword unexpected error: %v", err)
}
if loc != nil {
t.Fatalf("Keyword = %+v, want nil for a missing match", loc)
}
}
func TestKeyword_EmptyAndBlankQuery(t *testing.T) {
t.Parallel()
aud := NewContextAuditor(texts(model.RoleUser, "alpha"))
for _, q := range []string{"", " "} {
_, err := aud.Keyword(context.Background(), q)
if !errors.Is(err, ErrQueryEmpty) {
t.Fatalf("Keyword(%q) error = %v, want ErrQueryEmpty", q, err)
}
}
}
func TestKeyword_CanceledContext(t *testing.T) {
t.Parallel()
aud := NewContextAuditor(texts(model.RoleUser, "alpha"))
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, err := aud.Keyword(ctx, "alpha")
if !errors.Is(err, context.Canceled) {
t.Fatalf("Keyword error = %v, want context.Canceled", err)
}
}
func TestKeyword_FirstMatchOnly(t *testing.T) {
t.Parallel()
aud := NewContextAuditor(texts(model.RoleUser, "foo", "bar", "foo"))
loc, err := aud.Keyword(context.Background(), "foo")
if err != nil {
t.Fatalf("Keyword unexpected error: %v", err)
}
if loc.Line != 1 {
t.Fatalf("Line = %d, want 1 (earliest match)", loc.Line)
}
}
func TestKeyword_IgnoresImagePayload(t *testing.T) {
t.Parallel()
msgs := []model.Message{
model.TextMessage(model.RoleUser, "alpha"),
model.ImageMessage(model.RoleUser, "", "http://example.com/bravo.png"),
}
aud := NewContextAuditor(msgs)
loc, err := aud.Keyword(context.Background(), "bravo")
if err != nil {
t.Fatalf("Keyword unexpected error: %v", err)
}
if loc != nil {
t.Fatalf("Keyword matched an image URL (ignored): %+v", loc)
}
loc, err = aud.Keyword(context.Background(), "alpha")
if err != nil {
t.Fatalf("Keyword unexpected error: %v", err)
}
if loc == nil || loc.Line != 1 {
t.Fatalf("text-part match failed: line = %d", loc.Line)
}
}