92 lines
3.2 KiB
Go
92 lines
3.2 KiB
Go
package aiintake
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestExtractInputValidate(t *testing.T) {
|
|
valid := strings.Repeat("a", minTextLen)
|
|
tooShort := strings.Repeat("a", minTextLen-1)
|
|
tooLong := strings.Repeat("a", maxTextLen+1)
|
|
|
|
tests := []struct {
|
|
name string
|
|
text string
|
|
wantErr bool
|
|
}{
|
|
{"valid minimum length", valid, false},
|
|
{"empty text", "", true},
|
|
{"below minimum length", tooShort, true},
|
|
{"at maximum length", strings.Repeat("a", maxTextLen), false},
|
|
{"above maximum length", tooLong, true},
|
|
{"typical customer text", "ноутбук ASUS не включается, клиент Иван, телефон +79991234567", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
b := extractInput{Text: tt.text}
|
|
got := b.validate()
|
|
if (got != "") != tt.wantErr {
|
|
t.Errorf("validate() = %q, wantErr %v", got, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildGeminiRequestEmbedsTextBetweenMarkers(t *testing.T) {
|
|
text := "клиент сказал что принтер полосит"
|
|
req := buildGeminiRequest(text, "gemini-2.0-flash")
|
|
|
|
contents, ok := req["contents"].([]map[string]any)
|
|
if !ok || len(contents) != 1 {
|
|
t.Fatalf("expected exactly one content entry, got %#v", req["contents"])
|
|
}
|
|
parts, ok := contents[0]["parts"].([]map[string]any)
|
|
if !ok || len(parts) != 1 {
|
|
t.Fatalf("expected exactly one part, got %#v", contents[0]["parts"])
|
|
}
|
|
promptText, ok := parts[0]["text"].(string)
|
|
if !ok {
|
|
t.Fatalf("expected part text to be a string, got %#v", parts[0]["text"])
|
|
}
|
|
if !strings.Contains(promptText, text) {
|
|
t.Errorf("prompt does not contain the customer text: %q", promptText)
|
|
}
|
|
if !strings.Contains(promptText, "BEGIN CUSTOMER TEXT") || !strings.Contains(promptText, "END CUSTOMER TEXT") {
|
|
t.Error("prompt is missing the delimiter markers meant to fence off untrusted customer text from instructions")
|
|
}
|
|
|
|
genConfig, ok := req["generationConfig"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected generationConfig to be present, got %#v", req["generationConfig"])
|
|
}
|
|
responseFormat, ok := genConfig["responseFormat"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected responseFormat to be present, got %#v", genConfig["responseFormat"])
|
|
}
|
|
textFormat, ok := responseFormat["text"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected responseFormat.text to be present, got %#v", responseFormat["text"])
|
|
}
|
|
if textFormat["mimeType"] != "application/json" {
|
|
t.Errorf("expected mimeType application/json, got %#v", textFormat["mimeType"])
|
|
}
|
|
if textFormat["schema"] == nil {
|
|
t.Error("expected a non-nil response schema")
|
|
}
|
|
}
|
|
|
|
func TestBuildGeminiRequestDoesNotMutateSchemaBetweenCalls(t *testing.T) {
|
|
// extractionSchema is a shared package-level map — building two requests
|
|
// must not let one call's mutation bleed into the other's.
|
|
req1 := buildGeminiRequest("first text", "gemini-2.0-flash")
|
|
req2 := buildGeminiRequest("second text", "gemini-2.0-flash")
|
|
|
|
schema1 := req1["generationConfig"].(map[string]any)["responseFormat"].(map[string]any)["text"].(map[string]any)["schema"]
|
|
schema2 := req2["generationConfig"].(map[string]any)["responseFormat"].(map[string]any)["text"].(map[string]any)["schema"]
|
|
if schema1 == nil || schema2 == nil {
|
|
t.Fatal("expected non-nil schemas")
|
|
}
|
|
}
|