Files
jiang13-bbs/backend/service/brand_test.go
freefire 4f3f3a265c feat: 友链/书库/移动端导航/排行榜等多模块功能
新增模块:
- 友链(friendlink)后端处理 + 前端管理页与友链板
- 书库(library):导入、章节、封面、阅读页、横竖版自适应 AdaptiveCoverSlot
- 顶栏导航(header_nav)配置与 MobileTabBar/MobileRailDrawers 移动端抽屉
- 排行榜 service 测试、站点页面测试、时间线发布(timeline_release)

其它改动:
- 后端 handlers/services 全量小幅调整
- 前端组件、库函数、URL/品牌/站点 URL 工具更新
- Lightbox 图片、MdEntries 条目卡、coverColor 派生色相等前端能力
2026-09-30 16:30:07 +08:00

171 lines
5.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"errors"
"os"
"testing"
)
func TestOpenBrandFile(t *testing.T) {
s, dir := newMediaLibraryService(t)
png := "/uploads/brand/0123456789abcdef0123456789abcdef.png"
if _, err := s.OpenBrandFile(png); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("missing file want ErrNotExist, got %v", err)
}
writeMediaFile(t, dir, "brand/0123456789abcdef0123456789abcdef.png", []byte("png"))
f, err := s.OpenBrandFile(png)
if err != nil {
t.Fatal(err)
}
f.Close()
for _, bad := range []string{
"",
"/uploads/images/0123456789abcdef0123456789abcdef.png",
"/uploads/brand/../avatars/x.png",
"http://evil.test/x.png",
} {
if _, err := s.OpenBrandFile(bad); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("should reject %q, got %v", bad, err)
}
}
}
func TestNormalizeBrandURL(t *testing.T) {
png := "/uploads/brand/0123456789abcdef0123456789abcdef.png"
got, ok := NormalizeBrandURL(BrandSlotLight, png)
if !ok || got != png {
t.Fatalf("logo png want %s got %q ok=%v", png, got, ok)
}
ico := "/uploads/brand/0123456789abcdef0123456789abcdef.ico"
if _, ok := NormalizeBrandURL(BrandSlotLight, ico); ok {
t.Fatal("logo should reject ico")
}
got, ok = NormalizeBrandURL(BrandSlotFavicon, ico)
if !ok || got != ico {
t.Fatalf("favicon ico want %s got %q ok=%v", ico, got, ok)
}
empty, ok := NormalizeBrandURL(BrandSlotDark, " ")
if !ok || empty != "" {
t.Fatalf("empty should clear, got %q ok=%v", empty, ok)
}
rejects := []string{
"http://evil.test/x.png",
"/uploads/brand/../avatars/x.png",
"/uploads/backgrounds/0123456789abcdef0123456789abcdef.png",
"/uploads/brand/short.png",
"javascript:alert(1)",
}
for _, u := range rejects {
if _, ok := NormalizeBrandURL(BrandSlotFavicon, u); ok {
t.Fatalf("should reject %q", u)
}
}
}
func TestNormalizeKeywords(t *testing.T) {
got, err := NormalizeKeywords([]string{" Go , gin ", "论坛,Go"})
if err != nil {
t.Fatal(err)
}
if len(got) != 3 || got[0] != "Go" || got[1] != "gin" || got[2] != "论坛" {
t.Fatalf("unexpected %v", got)
}
long := ""
for i := 0; i < MaxKeywordRunes+1; i++ {
long += "字"
}
if _, err := NormalizeKeywords([]string{long}); err == nil {
t.Fatal("overlong keyword should fail")
}
many := make([]string, MaxKeywordCount+1)
for i := range many {
many[i] = string(rune('a' + i))
}
if _, err := NormalizeKeywords(many); err == nil {
t.Fatal("too many keywords should fail")
}
}
func TestNormalizeFooterLinks(t *testing.T) {
got, err := NormalizeFooterLinks([]FooterLink{
{Label: "备案", URL: "https://beian.miit.gov.cn/", NewTab: true, Align: FooterLinkAlignRight},
{Label: "关于", URL: "/about", NewTab: false, Align: FooterLinkAlignLeft},
})
if err != nil || len(got) != 2 || got[1].URL != "/about" || got[1].Align != FooterLinkAlignLeft {
t.Fatalf("got %+v err=%v", got, err)
}
bad := []FooterLink{
{Label: "x", URL: "javascript:alert(1)"},
{Label: "x", URL: "//evil.test"},
{Label: "", URL: "/a"},
{Label: "x", URL: "ftp://files.test/a"},
{Label: "x", URL: "/ok", Align: "middle"},
}
for _, item := range bad {
if _, err := NormalizeFooterLinks([]FooterLink{item}); err == nil {
t.Fatalf("should reject %+v", item)
}
}
raw := `[{"label":"ICP","url":"https://beian.miit.gov.cn/"}]`
parsed, err := parseFooterLinksJSON(raw)
if err != nil || len(parsed) != 1 || !parsed[0].NewTab || parsed[0].Align != FooterLinkAlignRight {
t.Fatalf("external default new tab + right align, got %+v err=%v", parsed, err)
}
}
func TestNormalizeFooterLinkAlign(t *testing.T) {
cases := []struct {
in string
want string
ok bool
}{
{"", FooterLinkAlignRight, true},
{" right ", FooterLinkAlignRight, true},
{"left", FooterLinkAlignLeft, true},
{"center", FooterLinkAlignCenter, true},
{"middle", "", false},
}
for _, tc := range cases {
got, ok := NormalizeFooterLinkAlign(tc.in)
if ok != tc.ok || got != tc.want {
t.Fatalf("in=%q got=%q ok=%v want=%q/%v", tc.in, got, ok, tc.want, tc.ok)
}
}
}
func TestNormalizeBrandMarkAndSize(t *testing.T) {
mark, ok := NormalizeBrandMark(" image ")
if !ok || mark != BrandMarkImage {
t.Fatalf("mark got %q ok=%v", mark, ok)
}
mark, ok = NormalizeBrandMark("")
if !ok || mark != BrandMarkImageText {
t.Fatalf("empty mark should default, got %q", mark)
}
if _, ok := NormalizeBrandMark("banner"); ok {
t.Fatal("unknown mark should fail")
}
size, ok := NormalizeBrandLogoSize("4x1")
if !ok || size != BrandLogoSize4x1 {
t.Fatalf("size got %q", size)
}
size, ok = NormalizeBrandLogoSize("")
if !ok || size != BrandLogoSizeSQ {
t.Fatalf("empty size should default, got %q", size)
}
if _, ok := NormalizeBrandLogoSize("xl"); ok {
t.Fatal("old height preset should fail")
}
fit, ok := NormalizeBrandLogoFit("repeat")
if !ok || fit != BrandLogoFitRepeat {
t.Fatalf("fit got %q", fit)
}
fit, ok = NormalizeBrandLogoFit("")
if !ok || fit != BrandLogoFitContain {
t.Fatalf("empty fit should default, got %q", fit)
}
if _, ok := NormalizeBrandLogoFit("zoom"); ok {
t.Fatal("unknown fit should fail")
}
}