Files
qitongxue-api/internal/logic/admin_test.go

68 lines
2.1 KiB
Go
Raw Normal View History

2026-09-29 10:57:01 +08:00
package logic
import "testing"
// TestResolveSort_WhitelistHit 白名单命中的列应原样返回,方向按 asc/desc 归一。
func TestResolveSort_WhitelistHit(t *testing.T) {
wl := map[string]string{"created_at": "created_at", "usage_count": "usage_count"}
col, dir := resolveSort("created_at", "asc", wl, "id desc")
if col != "created_at" || dir != "asc" {
t.Fatalf("hit asc: got (%q,%q)", col, dir)
}
// 方向大写也应被识别
col, dir = resolveSort("usage_count", "ASC", wl, "id desc")
if col != "usage_count" || dir != "asc" {
t.Fatalf("hit ASC: got (%q,%q)", col, dir)
}
}
// TestResolveSort_DefaultDirection 命中白名单但未给方向时,默认 desc。
func TestResolveSort_DefaultDirection(t *testing.T) {
wl := map[string]string{"created_at": "created_at"}
col, dir := resolveSort("created_at", "", wl, "id desc")
if col != "created_at" || dir != "desc" {
t.Fatalf("default dir: got (%q,%q)", col, dir)
}
}
// TestResolveSort_FallbackParsed fallback 形如 "列名 方向" 时按解析结果返回。
func TestResolveSort_FallbackParsed(t *testing.T) {
wl := map[string]string{"created_at": "created_at"}
col, dir := resolveSort("", "", wl, "id desc")
if col != "id" || dir != "desc" {
t.Fatalf("empty sortBy fallback: got (%q,%q)", col, dir)
}
col, dir = resolveSort("nope", "", wl, "sort asc")
if col != "sort" || dir != "asc" {
t.Fatalf("unknown sortBy fallback: got (%q,%q)", col, dir)
}
// 只有列名、无方向时默认 desc
col, dir = resolveSort("", "", wl, "sort")
if col != "sort" || dir != "desc" {
t.Fatalf("single-token fallback: got (%q,%q)", col, dir)
}
}
// TestResolveSort_InjectionRejected 非法 sortBy(未在白名单)必须回落到 fallback,
// 绝不能把用户输入拼进 ORDER BY。
func TestResolveSort_InjectionRejected(t *testing.T) {
wl := map[string]string{"created_at": "created_at"}
for _, evil := range []string{
"created_at; DROP TABLE users",
"id)--",
"(SELECT 1)",
"created_at DESC, id",
} {
col, _ := resolveSort(evil, "asc", wl, "id desc")
if col != "id" {
t.Fatalf("injection %q not rejected, got col=%q", evil, col)
}
}
}