main_test.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package main
  2. import "testing"
  3. // TestSplitFlagsAndArgs 锁住「flags 与位置参数任意顺序」这条。
  4. //
  5. // 这条不是洁癖:`spdump columns t_campus -db yuansiwei_2026` 这种直觉写法若丢掉了 `-db`,
  6. // 工具会连到默认库、查不到列、打印 "(0 行)" —— 一个看起来正常的错误答案。
  7. func TestSplitFlagsAndArgs(t *testing.T) {
  8. valueFlags := map[string]bool{"-db": true, "--db": true, "-like": true, "--like": true}
  9. cases := []struct {
  10. name string
  11. in []string
  12. wantFlags []string
  13. wantPos []string
  14. }{
  15. {
  16. name: "flags 在前",
  17. in: []string{"-db", "yuansiwei_2026", "t_campus"},
  18. wantFlags: []string{"-db", "yuansiwei_2026"},
  19. wantPos: []string{"t_campus"},
  20. },
  21. {
  22. name: "flags 在后(直觉写法,必须支持)",
  23. in: []string{"t_campus", "-db", "yuansiwei_2026"},
  24. wantFlags: []string{"-db", "yuansiwei_2026"},
  25. wantPos: []string{"t_campus"},
  26. },
  27. {
  28. name: "等号形式",
  29. in: []string{"t_campus", "-db=yuansiwei"},
  30. wantFlags: []string{"-db=yuansiwei"},
  31. wantPos: []string{"t_campus"},
  32. },
  33. {
  34. name: "两个值型 flag 交错",
  35. in: []string{"x", "-like", "%a%", "-db", "finance_bk"},
  36. wantFlags: []string{"-like", "%a%", "-db", "finance_bk"},
  37. wantPos: []string{"x"},
  38. },
  39. {
  40. name: "纯位置参数",
  41. in: []string{"sp_user_expense_baddebt", "sp_user_expense_recharge"},
  42. wantFlags: nil,
  43. wantPos: []string{"sp_user_expense_baddebt", "sp_user_expense_recharge"},
  44. },
  45. {
  46. name: "SQL 语句里的短横线不能被当 flag",
  47. in: []string{"-db", "finance_bk", "select * from t where a=-1"},
  48. wantFlags: []string{"-db", "finance_bk"},
  49. wantPos: []string{"select * from t where a=-1"},
  50. },
  51. }
  52. for _, c := range cases {
  53. gotFlags, gotPos := splitFlagsAndArgs(c.in, valueFlags)
  54. if !eq(gotFlags, c.wantFlags) {
  55. t.Errorf("%s:flags = %v, want %v", c.name, gotFlags, c.wantFlags)
  56. }
  57. if !eq(gotPos, c.wantPos) {
  58. t.Errorf("%s:pos = %v, want %v", c.name, gotPos, c.wantPos)
  59. }
  60. }
  61. }
  62. func eq(a, b []string) bool {
  63. if len(a) != len(b) {
  64. return false
  65. }
  66. for i := range a {
  67. if a[i] != b[i] {
  68. return false
  69. }
  70. }
  71. return true
  72. }
  73. // TestReadOnlyPrefixes 保证 `sql` 子命令只放行只读语句的前缀判断是可靠的。
  74. func TestReadOnlyPrefixes(t *testing.T) {
  75. allowed := []string{"select 1", "SELECT * FROM t", "show create table t", "desc t", "explain select 1"}
  76. for _, s := range allowed {
  77. if !allowedSQL(s) {
  78. t.Errorf("应当放行:%q", s)
  79. }
  80. }
  81. denied := []string{
  82. "update t set a=1",
  83. "delete from t",
  84. "drop table t",
  85. "insert into t values (1)",
  86. "select 1; drop table t", // 分号后第二条 → 拒绝
  87. "",
  88. }
  89. for _, s := range denied {
  90. if allowedSQL(s) {
  91. t.Errorf("应当拒绝:%q", s)
  92. }
  93. }
  94. }