Compare commits

..

No commits in common. "main" and "v1.5.3" have entirely different histories.
main ... v1.5.3

5 changed files with 13 additions and 43 deletions

View File

@ -1,11 +1,5 @@
# CHANGELOG # 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) ## v1.5.3 (2026-06-21)
- **重构与错误堆栈支持**: - **重构与错误堆栈支持**:
- 重构 `js_export.go`,将 `FromJSON` 匿名函数改为具名函数 `jsFromJSON` - 重构 `js_export.go`,将 `FromJSON` 匿名函数改为具名函数 `jsFromJSON`

View File

@ -1,9 +1,5 @@
# 测试报告 (Test Report) # 测试报告 (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) ## 覆盖场景 (Coverage Scenarios)
- **语义化转换**: `To[T]``As` 覆盖基础类型、Slice、Map 及智能 JSON 自动穿透转换。 - **语义化转换**: `To[T]``As` 覆盖基础类型、Slice、Map 及智能 JSON 自动穿透转换。
- **核心类型转换**: `Int64`, `Uint64`, `Float64`, `Bool`, `String`, `time.Time`,包括边界值、零值及非法字符串输入。 - **核心类型转换**: `Int64`, `Uint64`, `Float64`, `Bool`, `String`, `time.Time`,包括边界值、零值及非法字符串输入。

24
cast.go
View File

@ -954,27 +954,19 @@ func FillSlice(target any, source any) {
// 补充缺失的 Key 转换工具 // 补充缺失的 Key 转换工具
func GetLowerName(s string) string { func GetLowerName(s string) string {
if len(s) == 0 { if len(s) > 0 && s[0] >= 'A' && s[0] <= 'Z' {
return s hasLower := false
}
if s[0] < 'A' || s[0] > 'Z' {
return s
}
n := 0
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
if s[i] >= 'A' && s[i] <= 'Z' { if s[i] >= 'a' && s[i] <= 'z' {
n++ hasLower = true
} else {
break break
} }
} }
if n == len(s) { if hasLower {
return strings.ToLower(s)
}
if n > 1 {
return strings.ToLower(s[:n-1]) + s[n-1:]
}
return strings.ToLower(s[:1]) + s[1:] return strings.ToLower(s[:1]) + s[1:]
}
}
return s
} }
func GetUpperName(s string) string { func GetUpperName(s string) string {

View File

@ -109,19 +109,7 @@ func TestPointerHelpers(t *testing.T) {
func TestNameConversions(t *testing.T) { func TestNameConversions(t *testing.T) {
if cast.GetLowerName("UserName") != "userName" { if cast.GetLowerName("UserName") != "userName" {
t.Error("GetLowerName UserName failed") t.Error("GetLowerName 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" { if cast.GetUpperName("userName") != "UserName" {
t.Error("GetUpperName failed") t.Error("GetUpperName failed")

View File

@ -18,7 +18,7 @@ func TestToMap(t *testing.T) {
u := User{Base: Base{ID: 1}, Name: "Tom"} u := User{Base: Base{ID: 1}, Name: "Tom"}
m1 := make(map[string]any) m1 := make(map[string]any)
cast.FillMap(m1, u) 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) t.Errorf("Struct inheritance to map failed: %v", m1)
} }