package systemconfig import "testing" func TestNormalizeHomeBannersMigratesLegacyImageURL(t *testing.T) { items := normalizeHomeBanners([]HomeBannerItem{ {Title: "旧结构", ImageURL: " https://cdn.example/legacy.png "}, }) if len(items) != 1 { t.Fatalf("期望保留 1 条轮播,实际 %d", len(items)) } if items[0].PC.ImageURL != "https://cdn.example/legacy.png" { t.Fatalf("旧图未迁移到 PC 端:%q", items[0].PC.ImageURL) } if items[0].Mobile.ImageURL != "https://cdn.example/legacy.png" { t.Fatalf("旧图未迁移到移动端:%q", items[0].Mobile.ImageURL) } if items[0].ImageURL != "" { t.Fatalf("旧字段应被清空,实际 %q", items[0].ImageURL) } } func TestNormalizeHomeBannersKeepsPerPlatformVisual(t *testing.T) { items := normalizeHomeBanners([]HomeBannerItem{{ Title: "两端分图", PC: HomeBannerVisual{ImageURL: " https://cdn.example/pc.png "}, Mobile: HomeBannerVisual{ImageURL: " https://cdn.example/mobile.png "}, }}) if items[0].PC.ImageURL != "https://cdn.example/pc.png" { t.Fatalf("PC 图被改动:%q", items[0].PC.ImageURL) } if items[0].Mobile.ImageURL != "https://cdn.example/mobile.png" { t.Fatalf("移动端图被改动:%q", items[0].Mobile.ImageURL) } } func TestNormalizeHomeBannersClampsHotspots(t *testing.T) { items := normalizeHomeBanners([]HomeBannerItem{{ Title: "热区", PC: HomeBannerVisual{Hotspots: []HomeBannerHotspot{ {ID: " h1 ", X: 90, Y: 95, Width: 20, Height: 20, Action: HomeBannerAction{Type: "route", Target: " /listings "}}, {ID: "zero", Width: 0, Height: 10, Action: HomeBannerAction{Type: "route", Target: "/x"}}, }}, }}) hotspots := items[0].PC.Hotspots if len(hotspots) != 1 { t.Fatalf("宽高为 0 的热区应被丢弃,剩余 %d 个", len(hotspots)) } if hotspots[0].ID != "h1" || hotspots[0].X != 80 || hotspots[0].Y != 80 { t.Fatalf("热区未收敛到合法范围:%+v", hotspots[0]) } if hotspots[0].Action.Type != "route" || hotspots[0].Action.Target != "/listings" { t.Fatalf("热区跳转未归一化:%+v", hotspots[0].Action) } } func TestNormalizeHomeBannersHotspotImageAndHoverScale(t *testing.T) { items := normalizeHomeBanners([]HomeBannerItem{{ Title: "热区按钮图", PC: HomeBannerVisual{Hotspots: []HomeBannerHotspot{ {ID: "a", Width: 10, Height: 10, ImageURL: " https://cdn.example/btn.png "}, {ID: "b", Width: 10, Height: 10, HoverScale: 9}, {ID: "c", Width: 10, Height: 10, HoverScale: 0.5}, }}, }}) hotspots := items[0].PC.Hotspots if hotspots[0].ImageURL != "https://cdn.example/btn.png" { t.Fatalf("热区按钮图未清理空白:%q", hotspots[0].ImageURL) } if hotspots[0].HoverScale != defaultBannerHotspotHoverScale { t.Fatalf("未配置悬浮倍数应回落默认值,实际 %v", hotspots[0].HoverScale) } if hotspots[1].HoverScale != maxBannerHotspotHoverScale { t.Fatalf("超上限的悬浮倍数应被收敛,实际 %v", hotspots[1].HoverScale) } if hotspots[2].HoverScale != 1 { t.Fatalf("小于 1 的悬浮倍数应收敛为 1,实际 %v", hotspots[2].HoverScale) } } func TestNormalizeBannerActionFallsBackToNone(t *testing.T) { cases := []struct { name string input HomeBannerAction expect HomeBannerAction }{ { name: "缺失目标的站内跳转退化为不跳转", input: HomeBannerAction{Type: "route", Target: " "}, expect: HomeBannerAction{Type: "none"}, }, { name: "未知类型退化为不跳转", input: HomeBannerAction{Type: "unknown", Target: "/x"}, expect: HomeBannerAction{Type: "none"}, }, { name: "查看大图不保留目标与新窗口", input: HomeBannerAction{Type: "preview", Target: "/x", OpenNewTab: true}, expect: HomeBannerAction{Type: "preview"}, }, { name: "外链保留新窗口标记", input: HomeBannerAction{Type: "link", Target: " https://cdn.example/a ", OpenNewTab: true}, expect: HomeBannerAction{Type: "link", Target: "https://cdn.example/a", OpenNewTab: true}, }, } for _, testCase := range cases { t.Run(testCase.name, func(t *testing.T) { if got := normalizeBannerAction(testCase.input); got != testCase.expect { t.Fatalf("期望 %+v,实际 %+v", testCase.expect, got) } }) } } func TestNormalizeHomeBannersFallsBackToDefaults(t *testing.T) { items := normalizeHomeBanners([]HomeBannerItem{{Title: " "}}) if len(items) != len(defaultHomeBanners()) { t.Fatalf("全部无效时应回落默认轮播,实际 %d 条", len(items)) } }