feat: 重构顺运宝规格主链路 (#88)
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
// Package spec 提供顺运宝规格身份键的唯一规范化实现。
|
||||
package spec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// MaxKeyRunes 是数据库 VARCHAR(191) 身份列允许的最大字符数。
|
||||
const MaxKeyRunes = 191
|
||||
|
||||
// SpecKey 把顺运宝规格原文规范化成稳定身份键。
|
||||
//
|
||||
// 它只去掉首尾空白并把连续空白折叠为一个空格,不做颜色、尺码或繁简
|
||||
// 推断。空规格和超过数据库列宽的规格返回错误,调用方不得截断。
|
||||
func SpecKey(raw string) (string, error) {
|
||||
key := strings.Join(strings.Fields(raw), " ")
|
||||
if key == "" {
|
||||
return "", fmt.Errorf("规格原文不能为空")
|
||||
}
|
||||
if utf8.RuneCountInString(key) > MaxKeyRunes {
|
||||
return "", fmt.Errorf("规格身份键超过 %d 个字符", MaxKeyRunes)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package spec
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSpecKey_只折叠空白(t *testing.T) {
|
||||
got, err := SpecKey(" 黑色,\tM【建議40-50公斤】 \n")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != "黑色, M【建議40-50公斤】" {
|
||||
t.Fatalf("SpecKey=%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpecKey_不依赖规格解析(t *testing.T) {
|
||||
got, err := SpecKey("紅色,3XL建議80-90公斤】")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != "紅色,3XL建議80-90公斤】" {
|
||||
t.Fatalf("SpecKey=%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpecKey_拒绝空值和超长值(t *testing.T) {
|
||||
if _, err := SpecKey(" \t\n "); err == nil {
|
||||
t.Fatal("空规格必须报错")
|
||||
}
|
||||
if _, err := SpecKey(strings.Repeat("规", MaxKeyRunes+1)); err == nil {
|
||||
t.Fatal("超长规格必须报错")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user