package windsurf import ( "encoding/base64" "testing" ) func TestValidateCascadeImages_AllowedMime(t *testing.T) { png := base64.StdEncoding.EncodeToString([]byte("\x89PNG\r\n\x1a\nfake")) tests := []struct { mime string wantErr bool }{ {"image/png", false}, {"image/jpeg", false}, {"image/gif", false}, {"image/svg+xml", false}, {"image/webp", true}, {"text/plain", true}, } for _, tt := range tests { imgs := []CascadeImage{{MimeType: tt.mime, Base64Data: png}} err := ValidateCascadeImages(imgs, DefaultCascadeImageValidationOptions()) if (err != nil) != tt.wantErr { t.Errorf("mime=%s err=%v wantErr=%v", tt.mime, err, tt.wantErr) } } } func TestValidateCascadeImages_CountLimit(t *testing.T) { png := base64.StdEncoding.EncodeToString([]byte("\x89PNG")) imgs := make([]CascadeImage, 6) for i := range imgs { imgs[i] = CascadeImage{MimeType: "image/png", Base64Data: png} } err := ValidateCascadeImages(imgs, DefaultCascadeImageValidationOptions()) if err == nil { t.Fatalf("expected count limit error") } } func TestValidateCascadeImages_InvalidBase64(t *testing.T) { imgs := []CascadeImage{{MimeType: "image/png", Base64Data: "!!!not-base64"}} err := ValidateCascadeImages(imgs, DefaultCascadeImageValidationOptions()) if err == nil { t.Fatalf("expected invalid base64 error") } } func TestValidateCascadeImages_EmptyData(t *testing.T) { imgs := []CascadeImage{{MimeType: "image/png", Base64Data: ""}} err := ValidateCascadeImages(imgs, DefaultCascadeImageValidationOptions()) if err == nil { t.Fatalf("expected empty data error") } } func TestValidateCascadeImages_ByteLimit(t *testing.T) { big := make([]byte, CascadeImageMaxBytes+1) imgs := []CascadeImage{{MimeType: "image/png", Base64Data: base64.StdEncoding.EncodeToString(big)}} err := ValidateCascadeImages(imgs, DefaultCascadeImageValidationOptions()) if err == nil { t.Fatalf("expected size limit error") } } func TestValidateCascadeImages_PopulatesDigest(t *testing.T) { png := base64.StdEncoding.EncodeToString([]byte("\x89PNG\r\n\x1a\nfake")) imgs := []CascadeImage{{MimeType: "image/PNG", Base64Data: png}} if err := ValidateCascadeImages(imgs, DefaultCascadeImageValidationOptions()); err != nil { t.Fatalf("unexpected error: %v", err) } if imgs[0].SHA256 == "" { t.Errorf("sha256 should be populated") } if imgs[0].ByteLen == 0 { t.Errorf("byteLen should be populated") } if imgs[0].MimeType != "image/png" { t.Errorf("mime should be normalized to lowercase, got %q", imgs[0].MimeType) } } func TestBuildImageDigests(t *testing.T) { imgs := []CascadeImage{ {MimeType: "image/png", SHA256: "abc", ByteLen: 10, Caption: "x", Base64Data: "ignored"}, {MimeType: "image/jpeg", SHA256: "def", ByteLen: 20}, } out := BuildImageDigests(imgs) if len(out) != 2 { t.Fatalf("expected 2 digests, got %d", len(out)) } if out[0].MimeType != "image/png" || out[0].SHA256 != "abc" || out[0].ByteLen != 10 || out[0].Caption != "x" { t.Errorf("digest[0] mismatch: %+v", out[0]) } // ImageDigest 不应包含 base64 字段 // (这个通过结构体字段检查,而非运行时 — 此处只是确认编译通过) } func TestComputeImageDigest(t *testing.T) { img := CascadeImage{MimeType: "IMAGE/PNG", Base64Data: base64.StdEncoding.EncodeToString([]byte("hello"))} if err := ComputeImageDigest(&img); err != nil { t.Fatalf("unexpected error: %v", err) } if img.ByteLen != 5 { t.Errorf("byteLen=%d want 5", img.ByteLen) } // sha256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 if img.SHA256 != "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" { t.Errorf("sha256 mismatch: %s", img.SHA256) } if img.MimeType != "image/png" { t.Errorf("mime not normalized: %s", img.MimeType) } }