norm_test.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package norm
  2. import "testing"
  3. // TestPhone 验证 phone 强归一规则(P0-06 §2.1 五步顺序)。
  4. func TestPhone(t *testing.T) {
  5. cases := []struct {
  6. name string
  7. raw string
  8. wantCanon string
  9. wantOK bool
  10. }{
  11. // 标准 11 位
  12. {"纯 11 位", "13800000000", "13800000000", true},
  13. {"前后空白", " 13800000000 ", "13800000000", true},
  14. // 去分隔符
  15. {"横线分隔", "138-0000-0000", "13800000000", true},
  16. {"点号分隔", "138.0000.0000", "13800000000", true},
  17. {"空格分隔", "138 0000 0000", "13800000000", true},
  18. // 国际前缀
  19. {"+86 前缀", "+8613800000000", "13800000000", true},
  20. {"0086 前缀", "008613800000000", "13800000000", true},
  21. {"86 前缀无加号", "8613800000000", "13800000000", true},
  22. {"0086 后非大陆号段", "008610800000000", "", false}, // 剥 0086 后 108... 号段不符 → 不剥,整体也非 11 位 → false
  23. {"86 后非大陆号段", "8610800000000", "", false},
  24. // 异常
  25. {"空串", "", "", false},
  26. {"仅空白", " ", "", false},
  27. {"10 位", "1380000000", "", false},
  28. {"12 位", "138000000001", "", false},
  29. {"号段不符 10 开头", "10800000000", "", false},
  30. {"号段不符 12 开头", "12800000000", "", false},
  31. {"含字母", "1380000000a", "", false},
  32. }
  33. for _, c := range cases {
  34. t.Run(c.name, func(t *testing.T) {
  35. got, ok := Phone(c.raw)
  36. if got != c.wantCanon || ok != c.wantOK {
  37. t.Fatalf("Phone(%q) = (%q, %v), want (%q, %v)", c.raw, got, ok, c.wantCanon, c.wantOK)
  38. }
  39. })
  40. }
  41. }
  42. // TestPhoneIdempotent 验证幂等性:归一(归一(x)) == 归一(x)。
  43. func TestPhoneIdempotent(t *testing.T) {
  44. raws := []string{"+8613800000000", "138-0000-0000", "138.0000.0000", " 13800000000 ", "8613800000000"}
  45. for _, raw := range raws {
  46. first, ok1 := Phone(raw)
  47. if !ok1 {
  48. t.Fatalf("Phone(%q) 首次归一失败,无法验证幂等", raw)
  49. }
  50. second, ok2 := Phone(first)
  51. if second != first || !ok2 {
  52. t.Fatalf("Phone 非幂等:Phone(%q)=(%q,%v) → 再归一 (%q,%v)", raw, first, ok1, second, ok2)
  53. }
  54. }
  55. }
  56. // TestWechatOpenID 验证 wechat openid 仅 trim。
  57. func TestWechatOpenID(t *testing.T) {
  58. cases := []struct {
  59. name string
  60. raw string
  61. wantCanon string
  62. wantOK bool
  63. }{
  64. {"标准", "openid_abc123", "openid_abc123", true},
  65. {"含空白", " openid_abc123 ", "openid_abc123", true},
  66. {"空串", "", "", false},
  67. {"仅空白", " ", "", false},
  68. }
  69. for _, c := range cases {
  70. t.Run(c.name, func(t *testing.T) {
  71. got, ok := WechatOpenID(c.raw)
  72. if got != c.wantCanon || ok != c.wantOK {
  73. t.Fatalf("WechatOpenID(%q) = (%q, %v), want (%q, %v)", c.raw, got, ok, c.wantCanon, c.wantOK)
  74. }
  75. })
  76. }
  77. }
  78. // TestEmail 验证 email 轻归一(trim + 小写 + 正则)。
  79. func TestEmail(t *testing.T) {
  80. cases := []struct {
  81. name string
  82. raw string
  83. wantCanon string
  84. wantOK bool
  85. }{
  86. {"标准", "User@Example.COM", "user@example.com", true},
  87. {"含空白", " user@example.com ", "user@example.com", true},
  88. {"保留 +tag", "user+tag@example.com", "user+tag@example.com", true},
  89. {"缺域名点", "user@examplecom", "", false},
  90. {"缺 @", "userexample.com", "", false},
  91. {"空串", "", "", false},
  92. }
  93. for _, c := range cases {
  94. t.Run(c.name, func(t *testing.T) {
  95. got, ok := Email(c.raw)
  96. if got != c.wantCanon || ok != c.wantOK {
  97. t.Fatalf("Email(%q) = (%q, %v), want (%q, %v)", c.raw, got, ok, c.wantCanon, c.wantOK)
  98. }
  99. })
  100. }
  101. }
  102. // TestUsername 验证 username 轻归一(trim + 小写,无 ok)。
  103. func TestUsername(t *testing.T) {
  104. cases := []struct {
  105. name string
  106. raw string
  107. want string
  108. }{
  109. {"标准", "ZhangSan", "zhangsan"},
  110. {"含空白", " ZhangSan ", "zhangsan"},
  111. {"空串", "", ""},
  112. {"已小写", "abc123", "abc123"},
  113. }
  114. for _, c := range cases {
  115. t.Run(c.name, func(t *testing.T) {
  116. got := Username(c.raw)
  117. if got != c.want {
  118. t.Fatalf("Username(%q) = %q, want %q", c.raw, got, c.want)
  119. }
  120. })
  121. }
  122. }