package main import "testing" // TestSplitFlagsAndArgs 锁住「flags 与位置参数任意顺序」这条。 // // 这条不是洁癖:`spdump columns t_campus -db yuansiwei_2026` 这种直觉写法若丢掉了 `-db`, // 工具会连到默认库、查不到列、打印 "(0 行)" —— 一个看起来正常的错误答案。 func TestSplitFlagsAndArgs(t *testing.T) { valueFlags := map[string]bool{"-db": true, "--db": true, "-like": true, "--like": true} cases := []struct { name string in []string wantFlags []string wantPos []string }{ { name: "flags 在前", in: []string{"-db", "yuansiwei_2026", "t_campus"}, wantFlags: []string{"-db", "yuansiwei_2026"}, wantPos: []string{"t_campus"}, }, { name: "flags 在后(直觉写法,必须支持)", in: []string{"t_campus", "-db", "yuansiwei_2026"}, wantFlags: []string{"-db", "yuansiwei_2026"}, wantPos: []string{"t_campus"}, }, { name: "等号形式", in: []string{"t_campus", "-db=yuansiwei"}, wantFlags: []string{"-db=yuansiwei"}, wantPos: []string{"t_campus"}, }, { name: "两个值型 flag 交错", in: []string{"x", "-like", "%a%", "-db", "finance_bk"}, wantFlags: []string{"-like", "%a%", "-db", "finance_bk"}, wantPos: []string{"x"}, }, { name: "纯位置参数", in: []string{"sp_user_expense_baddebt", "sp_user_expense_recharge"}, wantFlags: nil, wantPos: []string{"sp_user_expense_baddebt", "sp_user_expense_recharge"}, }, { name: "SQL 语句里的短横线不能被当 flag", in: []string{"-db", "finance_bk", "select * from t where a=-1"}, wantFlags: []string{"-db", "finance_bk"}, wantPos: []string{"select * from t where a=-1"}, }, } for _, c := range cases { gotFlags, gotPos := splitFlagsAndArgs(c.in, valueFlags) if !eq(gotFlags, c.wantFlags) { t.Errorf("%s:flags = %v, want %v", c.name, gotFlags, c.wantFlags) } if !eq(gotPos, c.wantPos) { t.Errorf("%s:pos = %v, want %v", c.name, gotPos, c.wantPos) } } } func eq(a, b []string) bool { if len(a) != len(b) { return false } for i := range a { if a[i] != b[i] { return false } } return true } // TestReadOnlyPrefixes 保证 `sql` 子命令只放行只读语句的前缀判断是可靠的。 func TestReadOnlyPrefixes(t *testing.T) { allowed := []string{"select 1", "SELECT * FROM t", "show create table t", "desc t", "explain select 1"} for _, s := range allowed { if !allowedSQL(s) { t.Errorf("应当放行:%q", s) } } denied := []string{ "update t set a=1", "delete from t", "drop table t", "insert into t values (1)", "select 1; drop table t", // 分号后第二条 → 拒绝 "", } for _, s := range denied { if allowedSQL(s) { t.Errorf("应当拒绝:%q", s) } } }