Files
ttstd-infinite-canvas/backend/internal/app/appearance_button_fill_test.go

116 lines
4.0 KiB
Go

package app
import (
"encoding/json"
"testing"
"yingce/backend/internal/model"
)
func TestAppearanceButtonFillRoundTripAndValidation(t *testing.T) {
svc, _, _, admin := newAppearanceTestService(t)
themes := defaultAppearanceSkinThemes()
custom := cloneAppearanceSkin(themes[0], "custom-gradient", "渐变主题", "主按钮渐变")
custom.Tokens.Buttons.Light.Angle = 45
custom.Tokens.Buttons.Light.Start = "#123456"
custom.Tokens.Buttons.Dark.Mode = "solid"
themes = append(themes, custom)
input := AppearanceSetting{BrandName: "测试站点", BrandSlug: "test", AuthHeroTitle: defaultAppearanceHeroTitle, SkinID: custom.ID, SkinThemes: themes}
saved, err := svc.UpdateAppearance(admin, input)
if err != nil {
t.Fatal(err)
}
if saved.Public.ActiveSkin.Tokens.Buttons != custom.Tokens.Buttons {
t.Fatal("public projection lost button parameters")
}
loaded, err := svc.AdminAppearance(admin)
if err != nil {
t.Fatal(err)
}
if loaded.Public.ActiveSkin.Tokens.Buttons != custom.Tokens.Buttons {
t.Fatal("stored button parameters changed")
}
for name, mutate := range map[string]func(*AppearanceSkinButtonFill){
"mode": func(fill *AppearanceSkinButtonFill) { fill.Mode = "image" },
"negative angle": func(fill *AppearanceSkinButtonFill) { fill.Angle = -1 },
"large angle": func(fill *AppearanceSkinButtonFill) { fill.Angle = 361 },
"css injection": func(fill *AppearanceSkinButtonFill) { fill.End = "red; background:url(x)" },
"missing color": func(fill *AppearanceSkinButtonFill) { fill.Foreground = "" },
} {
t.Run(name, func(t *testing.T) {
bad := input
bad.SkinThemes = append([]AppearanceSkinTheme(nil), themes...)
mutate(&bad.SkinThemes[len(themes)-1].Tokens.Buttons.Light)
if _, err := svc.UpdateAppearance(admin, bad); err == nil {
t.Fatal("invalid fill accepted")
}
})
}
input.SkinThemes[0].Tokens.Buttons.Light.Start = "#000000"
overwritten, err := svc.UpdateAppearance(admin, input)
if err != nil {
t.Fatal(err)
}
if overwritten.SkinThemes[0].Tokens.Buttons != defaultClassicAppearanceSkin().Tokens.Buttons {
t.Fatal("classic fill mutation was stored")
}
}
func TestAppearanceLegacyButtonFills(t *testing.T) {
themes := defaultAppearanceSkinThemes()
for index := range themes {
themes[index].Tokens.Buttons = AppearanceSkinButtons{}
}
migrated := normalizeAppearanceSkinThemes(themes)
if err := validateAppearanceSkinThemes(migrated, "classic"); err != nil {
t.Fatal(err)
}
for _, skin := range migrated {
expected := "solid"
if skin.ID == "classic" {
expected = "gradient"
}
if skin.Tokens.Buttons.Light.Mode != expected || skin.Tokens.Buttons.Dark.Mode != expected {
t.Fatalf("wrong fill for %s", skin.ID)
}
}
var fill AppearanceSkinButtonFill
if err := json.Unmarshal([]byte(`{"angle":1.5}`), &fill); err == nil {
t.Fatal("fractional angle accepted")
}
}
func TestAppearanceReadsLegacyButtonFillsByStoredIdentity(t *testing.T) {
svc, db, _, admin := newAppearanceTestService(t)
classic := defaultClassicAppearanceSkin()
custom := cloneAppearanceSkin(classic, "custom-legacy", "旧主题", "保持纯色")
encoded, err := json.Marshal([]AppearanceSkinTheme{custom, classic})
if err != nil {
t.Fatal(err)
}
var themes []map[string]any
if err := json.Unmarshal(encoded, &themes); err != nil {
t.Fatal(err)
}
for _, skin := range themes {
delete(skin["tokens"].(map[string]any), "buttons")
}
encoded, err = json.Marshal(map[string]any{"schemaVersion": 7, "skinId": custom.ID, "skinThemes": themes})
if err != nil {
t.Fatal(err)
}
if err := db.Create(&model.SystemSetting{Key: appearanceSettingKey, ValueJSON: string(encoded)}).Error; err != nil {
t.Fatal(err)
}
loaded, err := svc.AdminAppearance(admin)
if err != nil {
t.Fatal(err)
}
if loaded.Public.ActiveSkin.Tokens.Buttons.Light.Mode != "solid" || loaded.SkinThemes[1].Tokens.Buttons.Light.Mode != "gradient" {
t.Fatal("legacy fields inherited another theme's fill")
}
if err := validateAppearanceSkinThemes(loaded.SkinThemes, custom.ID); err != nil {
t.Fatal(err)
}
}