Files
rond-with-you/internal/setting/setting_test.go
T
2026-09-18 13:05:49 +08:00

134 lines
4.1 KiB
Go

package setting
import (
"context"
"database/sql"
"os"
"strings"
"testing"
_ "github.com/jackc/pgx/v5/stdlib"
)
func TestVisitorHomePath(t *testing.T) {
full := Default() // Pages 默认全开
noMap := full
noMap.Pages = []string{"places", "stats"}
cases := []struct {
name string
set Settings
want string
}{
{"默认停在主页", full, ""},
{"空值(历史配置)停在主页", func() Settings { s := full; s.VisitorHome = ""; return s }(), ""},
{"显式主页", func() Settings { s := full; s.VisitorHome = "home"; return s }(), ""},
{"跳到地图", func() Settings { s := full; s.VisitorHome = "map"; return s }(), "/map"},
{"跳到统计", func() Settings { s := full; s.VisitorHome = "stats"; return s }(), "/stats"},
{"目标页没对访客开放则不跳", noMap, ""},
{"非法值不跳", func() Settings { s := full; s.VisitorHome = "javascript:alert(1)"; return s }(), ""},
{"不给访客任何页面时不跳", func() Settings { s := full; s.Pages = nil; s.VisitorHome = "map"; return s }(), ""},
}
for _, c := range cases {
if got := c.set.VisitorHomePath(); got != c.want {
t.Errorf("%s: VisitorHomePath = %q,期望 %q", c.name, got, c.want)
}
}
}
func TestNormalizeVisitorHome(t *testing.T) {
for _, v := range []string{"", "home", "nope", "/map", "../admin", "MAP"} {
if got := NormalizeVisitorHome(v); got != VisitorHomeMain {
t.Errorf("NormalizeVisitorHome(%q) = %q,期望 %q", v, got, VisitorHomeMain)
}
}
for _, p := range AllPages {
if got := NormalizeVisitorHome(p.Key); got != p.Key {
t.Errorf("NormalizeVisitorHome(%q) = %q,期望原样保留", p.Key, got)
}
}
}
// TestVisitorHomeStore 覆盖存取:旧配置(没有该键)必须回落到主页,
// 而不是把零值当成「访客落地到空路径」。
// 只在库名带 test 的库上跑——它会改写 settings 里的 site 键,不能碰正式库。
func TestVisitorHomeStore(t *testing.T) {
dsn := os.Getenv("ROND_DSN")
if dsn == "" {
t.Skip("未设置 ROND_DSN")
}
if !strings.Contains(dsn, "test") {
t.Skipf("库名不含 test,跳过以免动到正式站的设置:%s", dsn)
}
db, err := sql.Open("pgx", dsn)
if err != nil {
t.Fatal(err)
}
defer db.Close()
ctx := context.Background()
st := Store{DB: db}
var orig []byte
had := true
if err := db.QueryRowContext(ctx, `SELECT value FROM settings WHERE key='site'`).Scan(&orig); err != nil {
if err != sql.ErrNoRows {
t.Fatal(err)
}
had = false
}
defer func() { // 还原原配置,别把测试库的设置留下改动
if had {
db.ExecContext(ctx, `UPDATE settings SET value=$1 WHERE key='site'`, orig)
} else {
db.ExecContext(ctx, `DELETE FROM settings WHERE key='site'`)
}
}()
set := func(raw string) {
if _, err := db.ExecContext(ctx, `INSERT INTO settings (key, value) VALUES ('site', $1)
ON CONFLICT (key) DO UPDATE SET value=$1`, []byte(raw)); err != nil {
t.Fatal(err)
}
}
// 旧配置:整个键都不存在 → 默认停在主页
set(`{"pages":["map","stats"]}`)
if s, err := st.Load(ctx); err != nil {
t.Fatal(err)
} else if s.VisitorHome != VisitorHomeMain {
t.Errorf("缺键时 VisitorHome = %q,期望 %q", s.VisitorHome, VisitorHomeMain)
}
// 正常往返
s, err := st.Load(ctx)
if err != nil {
t.Fatal(err)
}
s.VisitorHome = "map"
if err := st.Save(ctx, s); err != nil {
t.Fatal(err)
}
if s2, err := st.Load(ctx); err != nil {
t.Fatal(err)
} else if s2.VisitorHome != "map" {
t.Errorf("存回来成了 %q,期望 map", s2.VisitorHome)
}
// 库里被塞了非法值 → 读出来必须收敛到主页
set(`{"pages":["map"],"visitor_home":"/etc/passwd"}`)
if s3, err := st.Load(ctx); err != nil {
t.Fatal(err)
} else if s3.VisitorHome != VisitorHomeMain {
t.Errorf("非法值读出 %q,期望收敛为 %q", s3.VisitorHome, VisitorHomeMain)
}
// 目标页没开放时不跳(即便设置里写着 map)
set(`{"pages":["stats"],"visitor_home":"map"}`)
if s4, err := st.Load(ctx); err != nil {
t.Fatal(err)
} else if got := s4.VisitorHomePath(); got != "" {
t.Errorf("目标页未开放却仍要跳 %q", got)
}
}