147 lines
4.5 KiB
Go
147 lines
4.5 KiB
Go
package httpapi
|
|
|
|
import "testing"
|
|
|
|
func TestGeminiGenerateContentModelFromPath(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
prefix string
|
|
requestPath string
|
|
wantModel string
|
|
wantOK bool
|
|
}{
|
|
{
|
|
name: "v1beta model",
|
|
prefix: "/v1beta/models/",
|
|
requestPath: "/v1beta/models/gemini-2.5-flash:generateContent",
|
|
wantModel: "gemini-2.5-flash",
|
|
wantOK: true,
|
|
},
|
|
{
|
|
name: "v1 model",
|
|
prefix: "/v1/models/",
|
|
requestPath: "/v1/models/gemini-compatible:generateContent",
|
|
wantModel: "gemini-compatible",
|
|
wantOK: true,
|
|
},
|
|
{
|
|
name: "bare model path",
|
|
prefix: "/models/",
|
|
requestPath: "/models/gemini-image:generateContent",
|
|
wantModel: "gemini-image",
|
|
wantOK: true,
|
|
},
|
|
{
|
|
name: "wrong suffix",
|
|
prefix: "/v1beta/models/",
|
|
requestPath: "/v1beta/models/gemini-2.5-flash:countTokens",
|
|
wantOK: false,
|
|
},
|
|
{
|
|
name: "missing model",
|
|
prefix: "/v1beta/models/",
|
|
requestPath: "/v1beta/models/:generateContent",
|
|
wantOK: false,
|
|
},
|
|
{
|
|
name: "extra path segment",
|
|
prefix: "/v1beta/models/",
|
|
requestPath: "/v1beta/models/group/gemini-2.5-flash:generateContent",
|
|
wantOK: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
gotModel, gotOK := geminiGenerateContentModelFromPath(tt.prefix, tt.requestPath)
|
|
if gotOK != tt.wantOK || gotModel != tt.wantModel {
|
|
t.Fatalf("geminiGenerateContentModelFromPath() = %q, %v; want %q, %v", gotModel, gotOK, tt.wantModel, tt.wantOK)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGeminiImageTaskBodyMapsTextOnlyToImageGenerate(t *testing.T) {
|
|
mapping, err := geminiImageTaskBody("gemini-image", map[string]any{
|
|
"contents": []any{
|
|
map[string]any{"parts": []any{
|
|
map[string]any{"text": "draw"},
|
|
map[string]any{"text": "a cat"},
|
|
}},
|
|
},
|
|
"generationConfig": map[string]any{
|
|
"candidateCount": float64(2),
|
|
"imageConfig": map[string]any{
|
|
"aspectRatio": "16:9",
|
|
"imageSize": "2K",
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("map Gemini request: %v", err)
|
|
}
|
|
if mapping.Kind != "images.generations" || mapping.Body["modelType"] != "image_generate" {
|
|
t.Fatalf("unexpected mapping kind/body: %+v", mapping)
|
|
}
|
|
if mapping.Body["prompt"] != "draw\na cat" || mapping.Body["n"] != 2 || mapping.Body["aspect_ratio"] != "16:9" || mapping.Body["resolution"] != "2K" {
|
|
t.Fatalf("unexpected mapped body: %+v", mapping.Body)
|
|
}
|
|
}
|
|
|
|
func TestGeminiImageTaskBodyMapsInlineDataToImageEdit(t *testing.T) {
|
|
mapping, err := geminiImageTaskBody("gemini-image", map[string]any{
|
|
"contents": []any{
|
|
map[string]any{"parts": []any{
|
|
map[string]any{"text": "make it brighter"},
|
|
map[string]any{"inlineData": map[string]any{
|
|
"mimeType": "image/png",
|
|
"data": "aW1hZ2U=",
|
|
}},
|
|
}},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("map Gemini request: %v", err)
|
|
}
|
|
if mapping.Kind != "images.edits" || mapping.Body["modelType"] != "image_edit" {
|
|
t.Fatalf("unexpected mapping kind/body: %+v", mapping)
|
|
}
|
|
if mapping.Body["prompt"] != "make it brighter" || mapping.Body["image"] != "data:image/png;base64,aW1hZ2U=" {
|
|
t.Fatalf("unexpected mapped body: %+v", mapping.Body)
|
|
}
|
|
}
|
|
|
|
func TestGeminiGenerateContentResponseMapsURLAndUsage(t *testing.T) {
|
|
response := geminiGenerateContentResponse(map[string]any{
|
|
"data": []any{map[string]any{
|
|
"type": "image",
|
|
"url": "https://cdn.example/out.webp",
|
|
}},
|
|
"usage": map[string]any{
|
|
"prompt_tokens": 3,
|
|
"completion_tokens": 4,
|
|
"total_tokens": 7,
|
|
},
|
|
}, "gemini-image")
|
|
|
|
candidates := response["candidates"].([]any)
|
|
content := candidates[0].(map[string]any)["content"].(map[string]any)
|
|
parts := content["parts"].([]any)
|
|
fileData := parts[0].(map[string]any)["fileData"].(map[string]any)
|
|
if fileData["fileUri"] != "https://cdn.example/out.webp" || fileData["mimeType"] != "image/webp" {
|
|
t.Fatalf("unexpected fileData part: %+v", fileData)
|
|
}
|
|
usage := response["usageMetadata"].(map[string]any)
|
|
if usage["promptTokenCount"] != 3 || usage["candidatesTokenCount"] != 4 || usage["totalTokenCount"] != 7 {
|
|
t.Fatalf("unexpected usage metadata: %+v", usage)
|
|
}
|
|
}
|
|
|
|
func TestGeminiFileResponseShape(t *testing.T) {
|
|
response := geminiFileResponse("files/test", "https://cdn.example/input.png", "image/png", 12)
|
|
file := response["file"].(map[string]any)
|
|
if file["name"] != "files/test" || file["uri"] != "https://cdn.example/input.png" || file["mimeType"] != "image/png" || file["sizeBytes"] != "12" || file["state"] != "ACTIVE" {
|
|
t.Fatalf("unexpected file response: %+v", file)
|
|
}
|
|
}
|