| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- package norm
- import "testing"
- // TestPhone 验证 phone 强归一规则(P0-06 §2.1 五步顺序)。
- func TestPhone(t *testing.T) {
- cases := []struct {
- name string
- raw string
- wantCanon string
- wantOK bool
- }{
- // 标准 11 位
- {"纯 11 位", "13800000000", "13800000000", true},
- {"前后空白", " 13800000000 ", "13800000000", true},
- // 去分隔符
- {"横线分隔", "138-0000-0000", "13800000000", true},
- {"点号分隔", "138.0000.0000", "13800000000", true},
- {"空格分隔", "138 0000 0000", "13800000000", true},
- // 国际前缀
- {"+86 前缀", "+8613800000000", "13800000000", true},
- {"0086 前缀", "008613800000000", "13800000000", true},
- {"86 前缀无加号", "8613800000000", "13800000000", true},
- {"0086 后非大陆号段", "008610800000000", "", false}, // 剥 0086 后 108... 号段不符 → 不剥,整体也非 11 位 → false
- {"86 后非大陆号段", "8610800000000", "", false},
- // 异常
- {"空串", "", "", false},
- {"仅空白", " ", "", false},
- {"10 位", "1380000000", "", false},
- {"12 位", "138000000001", "", false},
- {"号段不符 10 开头", "10800000000", "", false},
- {"号段不符 12 开头", "12800000000", "", false},
- {"含字母", "1380000000a", "", false},
- }
- for _, c := range cases {
- t.Run(c.name, func(t *testing.T) {
- got, ok := Phone(c.raw)
- if got != c.wantCanon || ok != c.wantOK {
- t.Fatalf("Phone(%q) = (%q, %v), want (%q, %v)", c.raw, got, ok, c.wantCanon, c.wantOK)
- }
- })
- }
- }
- // TestPhoneIdempotent 验证幂等性:归一(归一(x)) == 归一(x)。
- func TestPhoneIdempotent(t *testing.T) {
- raws := []string{"+8613800000000", "138-0000-0000", "138.0000.0000", " 13800000000 ", "8613800000000"}
- for _, raw := range raws {
- first, ok1 := Phone(raw)
- if !ok1 {
- t.Fatalf("Phone(%q) 首次归一失败,无法验证幂等", raw)
- }
- second, ok2 := Phone(first)
- if second != first || !ok2 {
- t.Fatalf("Phone 非幂等:Phone(%q)=(%q,%v) → 再归一 (%q,%v)", raw, first, ok1, second, ok2)
- }
- }
- }
- // TestWechatOpenID 验证 wechat openid 仅 trim。
- func TestWechatOpenID(t *testing.T) {
- cases := []struct {
- name string
- raw string
- wantCanon string
- wantOK bool
- }{
- {"标准", "openid_abc123", "openid_abc123", true},
- {"含空白", " openid_abc123 ", "openid_abc123", true},
- {"空串", "", "", false},
- {"仅空白", " ", "", false},
- }
- for _, c := range cases {
- t.Run(c.name, func(t *testing.T) {
- got, ok := WechatOpenID(c.raw)
- if got != c.wantCanon || ok != c.wantOK {
- t.Fatalf("WechatOpenID(%q) = (%q, %v), want (%q, %v)", c.raw, got, ok, c.wantCanon, c.wantOK)
- }
- })
- }
- }
- // TestEmail 验证 email 轻归一(trim + 小写 + 正则)。
- func TestEmail(t *testing.T) {
- cases := []struct {
- name string
- raw string
- wantCanon string
- wantOK bool
- }{
- {"标准", "User@Example.COM", "user@example.com", true},
- {"含空白", " user@example.com ", "user@example.com", true},
- {"保留 +tag", "user+tag@example.com", "user+tag@example.com", true},
- {"缺域名点", "user@examplecom", "", false},
- {"缺 @", "userexample.com", "", false},
- {"空串", "", "", false},
- }
- for _, c := range cases {
- t.Run(c.name, func(t *testing.T) {
- got, ok := Email(c.raw)
- if got != c.wantCanon || ok != c.wantOK {
- t.Fatalf("Email(%q) = (%q, %v), want (%q, %v)", c.raw, got, ok, c.wantCanon, c.wantOK)
- }
- })
- }
- }
- // TestUsername 验证 username 轻归一(trim + 小写,无 ok)。
- func TestUsername(t *testing.T) {
- cases := []struct {
- name string
- raw string
- want string
- }{
- {"标准", "ZhangSan", "zhangsan"},
- {"含空白", " ZhangSan ", "zhangsan"},
- {"空串", "", ""},
- {"已小写", "abc123", "abc123"},
- }
- for _, c := range cases {
- t.Run(c.name, func(t *testing.T) {
- got := Username(c.raw)
- if got != c.want {
- t.Fatalf("Username(%q) = %q, want %q", c.raw, got, c.want)
- }
- })
- }
- }
|