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) } } }