From e7d92dd03a5d5ea28a748416ade09d39b7ab2306 Mon Sep 17 00:00:00 2001 From: AI Engineer Date: Sat, 4 Jul 2026 21:48:26 +0800 Subject: [PATCH] =?UTF-8?q?fix(cast):=20=E4=BF=AE=E5=A4=8D=20GetLowerName?= =?UTF-8?q?=20=E7=BC=A9=E5=86=99=E8=AF=8D=E8=BE=B9=E7=95=8C=E5=A4=A7?= =?UTF-8?q?=E5=86=99=E8=BD=AC=E6=8D=A2=E7=BC=BA=E9=99=B7=E5=B9=B6=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=EF=BC=88by=20AI?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ TEST.md | 4 ++++ cast.go | 30 +++++++++++++++++++----------- cast_test.go | 14 +++++++++++++- conversion_test.go | 2 +- 5 files changed, 43 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b9abe3..0f1b4c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## v1.5.4 (2026-07-04) +- **大写缩写驼峰转换修复**: + - 重构了 `GetLowerName` 算法逻辑,使其能按照业界的驼峰字母边界规则正确处理大写缩写词(如 `ID` $\rightarrow$ `id`,`IDTime` $\rightarrow$ `idTime`,`SHAURLName` $\rightarrow$ `shaurlName`,`API` $\rightarrow$ `api`)。 + - 修复了此前全大写字段(例如 `ID`)因没有包含任何小写字母而导致无法被转换为小写驼峰的遗留缺陷。 + - 在 `cast_test.go` 中补充了针对各类连续大写边界的单元测试用例,并修正了继承属性 `id` 的测试断言。 + ## v1.5.3 (2026-06-21) - **重构与错误堆栈支持**: - 重构 `js_export.go`,将 `FromJSON` 匿名函数改为具名函数 `jsFromJSON`。 diff --git a/TEST.md b/TEST.md index 444e0c9..958442b 100644 --- a/TEST.md +++ b/TEST.md @@ -1,5 +1,9 @@ # 测试报告 (Test Report) +## [v1.5.4] - 2026-07-04 +- **连续大写驼峰边界转换校验**: Verified `GetLowerName` correctly lowercases acronyms like `ID` to `id`, `IDTime` to `idTime`, `SHAURLName` to `shaurlName`, and `API` to `api`. +- **单测覆盖率**: All unit tests (including `TestNameConversions` and `TestToMap` regression tests) passed without issues. + ## 覆盖场景 (Coverage Scenarios) - **语义化转换**: `To[T]` 和 `As` 覆盖基础类型、Slice、Map 及智能 JSON 自动穿透转换。 - **核心类型转换**: `Int64`, `Uint64`, `Float64`, `Bool`, `String`, `time.Time`,包括边界值、零值及非法字符串输入。 diff --git a/cast.go b/cast.go index 8708ff2..b7a264a 100644 --- a/cast.go +++ b/cast.go @@ -954,19 +954,27 @@ func FillSlice(target any, source any) { // 补充缺失的 Key 转换工具 func GetLowerName(s string) string { - if len(s) > 0 && s[0] >= 'A' && s[0] <= 'Z' { - hasLower := false - for i := 0; i < len(s); i++ { - if s[i] >= 'a' && s[i] <= 'z' { - hasLower = true - break - } - } - if hasLower { - return strings.ToLower(s[:1]) + s[1:] + if len(s) == 0 { + return s + } + if s[0] < 'A' || s[0] > 'Z' { + return s + } + n := 0 + for i := 0; i < len(s); i++ { + if s[i] >= 'A' && s[i] <= 'Z' { + n++ + } else { + break } } - return s + if n == len(s) { + return strings.ToLower(s) + } + if n > 1 { + return strings.ToLower(s[:n-1]) + s[n-1:] + } + return strings.ToLower(s[:1]) + s[1:] } func GetUpperName(s string) string { diff --git a/cast_test.go b/cast_test.go index cc61c84..366ad54 100644 --- a/cast_test.go +++ b/cast_test.go @@ -109,7 +109,19 @@ func TestPointerHelpers(t *testing.T) { func TestNameConversions(t *testing.T) { if cast.GetLowerName("UserName") != "userName" { - t.Error("GetLowerName failed") + t.Error("GetLowerName UserName failed") + } + if cast.GetLowerName("ID") != "id" { + t.Errorf("GetLowerName ID failed: expected id, got %s", cast.GetLowerName("ID")) + } + if cast.GetLowerName("IDTime") != "idTime" { + t.Errorf("GetLowerName IDTime failed: expected idTime, got %s", cast.GetLowerName("IDTime")) + } + if cast.GetLowerName("SHAURLName") != "shaurlName" { + t.Errorf("GetLowerName SHAURLName failed: expected shaurlName, got %s", cast.GetLowerName("SHAURLName")) + } + if cast.GetLowerName("API") != "api" { + t.Errorf("GetLowerName API failed: expected api, got %s", cast.GetLowerName("API")) } if cast.GetUpperName("userName") != "UserName" { t.Error("GetUpperName failed") diff --git a/conversion_test.go b/conversion_test.go index df9050c..ae505f1 100644 --- a/conversion_test.go +++ b/conversion_test.go @@ -18,7 +18,7 @@ func TestToMap(t *testing.T) { u := User{Base: Base{ID: 1}, Name: "Tom"} m1 := make(map[string]any) cast.FillMap(m1, u) - if m1["ID"] != 1 || m1["name"] != "Tom" { + if m1["id"] != 1 || m1["name"] != "Tom" { t.Errorf("Struct inheritance to map failed: %v", m1) }