Files
digital-psychology/apps/api/internal/avatar/store_test.go
T
jackyu66gitandCursor 89756f65b4 feat(ECR-012–016): 合规、题库、时辰刷新、头像、MBTI OEJTS 与埋点
落地输入合规、探索题库、报告日/时辰刷新、账号头像、OEJTS 量表,并补齐 H5 埋点与 Admin 漏斗;同步 ESS 工件、切至自建 Git、清理 GitHub Actions。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-13 01:27:58 +08:00

113 lines
2.8 KiB
Go

package avatar
import (
"bytes"
"mime/multipart"
"net/textproto"
"os"
"path/filepath"
"testing"
"github.com/google/uuid"
)
func TestResolveAbsRejectsTraversal(t *testing.T) {
dir := t.TempDir()
id := uuid.New()
name := id.String() + ".jpg"
if err := os.WriteFile(filepath.Join(dir, name), []byte("x"), 0o644); err != nil {
t.Fatal(err)
}
if _, err := ResolveAbs(dir, "../"+name); err == nil {
t.Fatal("expected reject ..")
}
if _, err := ResolveAbs(dir, "not-a-uuid.jpg"); err == nil {
t.Fatal("expected reject bad id")
}
if _, err := ResolveAbs(dir, id.String()+".gif"); err == nil {
t.Fatal("expected reject gif")
}
full, err := ResolveAbs(dir, name)
if err != nil {
t.Fatal(err)
}
if filepath.Base(full) != name {
t.Fatalf("full=%s", full)
}
}
func TestStoreRejectsBadTypeAndSize(t *testing.T) {
dir := t.TempDir()
uid := uuid.New()
fhExe := mustFormFile(t, "x.exe", "application/octet-stream", []byte("MZ"))
if _, err := Store(dir, uid, fhExe); err == nil {
t.Fatal("expected bad type")
}
big := bytes.Repeat([]byte("a"), MaxBytes+10)
fhBig := mustFormFile(t, "big.jpg", "image/jpeg", big)
if _, err := Store(dir, uid, fhBig); err == nil {
t.Fatal("expected too large")
}
}
func TestStoreOKAndOverwrite(t *testing.T) {
dir := t.TempDir()
uid := uuid.New()
fh := mustFormFile(t, "a.png", "image/png", []byte{0x89, 0x50, 0x4e, 0x47})
path, err := Store(dir, uid, fh)
if err != nil {
t.Fatal(err)
}
want := "/api/v1/media/avatars/" + uid.String() + ".png"
if path != want {
t.Fatalf("path=%s want=%s", path, want)
}
if _, err := os.Stat(filepath.Join(dir, uid.String()+".png")); err != nil {
t.Fatal(err)
}
fh2 := mustFormFile(t, "b.jpg", "image/jpeg", []byte{0xff, 0xd8, 0xff})
path2, err := Store(dir, uid, fh2)
if err != nil {
t.Fatal(err)
}
if path2 != "/api/v1/media/avatars/"+uid.String()+".jpg" {
t.Fatalf("path2=%s", path2)
}
if _, err := os.Stat(filepath.Join(dir, uid.String()+".png")); !os.IsNotExist(err) {
t.Fatal("old png should be removed")
}
}
func mustFormFile(t *testing.T, filename, contentType string, data []byte) *multipart.FileHeader {
t.Helper()
var buf bytes.Buffer
w := multipart.NewWriter(&buf)
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition", `form-data; name="file"; filename="`+filename+`"`)
h.Set("Content-Type", contentType)
part, err := w.CreatePart(h)
if err != nil {
t.Fatal(err)
}
if _, err := part.Write(data); err != nil {
t.Fatal(err)
}
if err := w.Close(); err != nil {
t.Fatal(err)
}
r := multipart.NewReader(&buf, w.Boundary())
form, err := r.ReadForm(int64(len(data)) + 1024)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = form.RemoveAll() })
files := form.File["file"]
if len(files) == 0 {
t.Fatal("no file part")
}
return files[0]
}