reflux/rfx_map_case_test.go
what 72d670be0b feat: 增强 map 大小写不敏感支持和函数重命名
- 新增 tryMapFieldKey 函数,返回 map 中实际存在的键(支持大小写转换)
- 优化 setFieldValue 方法,使用 tryMapFieldKey 查找已存在字段并更新
- 优化 setNestedValue 方法,修复嵌套 map 大小写处理和 interface 包装问题
- 重命名函数以提高代码清晰度:
  - tryStructField → tryStructFieldValue
  - tryMapField → tryMapFieldValue
  - tryMapFieldWithKey → tryMapFieldKey
- 新增 rfx_map_case_test.go 包含 16 个测试用例,覆盖基本、嵌套、边界等场景
2025-12-09 16:55:13 +08:00

436 lines
10 KiB
Go

package reflux
import "testing"
// TestMapCaseInsensitiveKeys 测试 map 大小写不敏感的键访问
func TestMapCaseInsensitiveKeys(t *testing.T) {
t.Run("Get with lowercase key when map has uppercase", func(t *testing.T) {
m := map[string]any{
"name": "Alice",
"age": 30,
}
rfx := New(&m)
// 使用大写键访问小写键
name := rfx.Get("Name").String()
if name != "Alice" {
t.Errorf("Expected 'Alice', got '%s'", name)
}
age := rfx.Get("Age").Int()
if age != 30 {
t.Errorf("Expected 30, got %d", age)
}
})
t.Run("Set with uppercase key to map with lowercase keys", func(t *testing.T) {
m := map[string]any{
"name": "Alice",
}
rfx := New(&m)
// 使用大写键设置值
rfx.Set("Name", "Bob")
// 验证小写键被更新
if m["name"] != "Bob" {
t.Errorf("Expected 'Bob', got '%v'", m["name"])
}
})
t.Run("Set with lowercase key creates new entry", func(t *testing.T) {
m := map[string]any{
"Name": "Alice",
}
rfx := New(&m)
// 使用小写键设置值(应该创建新条目)
rfx.Set("age", 25)
// 验证新条目被创建
if m["age"] != 25 {
t.Errorf("Expected 25, got '%v'", m["age"])
}
// 验证原始大写键仍然存在
if m["Name"] != "Alice" {
t.Errorf("Expected 'Alice', got '%v'", m["Name"])
}
})
t.Run("Exists with case-insensitive key", func(t *testing.T) {
m := map[string]any{
"name": "Alice",
}
rfx := New(&m)
// 使用大写键检查是否存在
if !rfx.Exists("Name") {
t.Error("Expected key 'Name' to exist (case-insensitive)")
}
// 使用小写键检查
if !rfx.Exists("name") {
t.Error("Expected key 'name' to exist")
}
})
}
// TestMapNestedCaseInsensitiveKeys 测试嵌套 map 的大小写不敏感访问
func TestMapNestedCaseInsensitiveKeys(t *testing.T) {
t.Run("Get nested map with mixed case keys", func(t *testing.T) {
m := map[string]any{
"user": map[string]any{
"name": "Alice",
"age": 30,
},
}
rfx := New(&m)
// 使用大写键访问嵌套的小写键
name := rfx.Get("User", "Name").String()
if name != "Alice" {
t.Errorf("Expected 'Alice', got '%s'", name)
}
age := rfx.Get("User", "Age").Int()
if age != 30 {
t.Errorf("Expected 30, got %d", age)
}
})
t.Run("Set nested map with mixed case keys", func(t *testing.T) {
m := map[string]any{
"user": map[string]any{
"name": "Alice",
},
}
rfx := New(&m)
// 使用大写键设置嵌套值
rfx.Set("User.Name", "Bob")
// 验证值被更新
userMap := m["user"].(map[string]any)
if userMap["name"] != "Bob" {
t.Errorf("Expected 'Bob', got '%v'", userMap["name"])
}
})
t.Run("Set deeply nested map with case-insensitive keys", func(t *testing.T) {
m := map[string]any{
"data": map[string]any{
"user": map[string]any{
"profile": map[string]any{
"name": "Alice",
},
},
},
}
rfx := New(&m)
// 使用大写键访问深层嵌套
rfx.Set("Data.User.Profile.Name", "Charlie")
// 验证值被更新
dataMap := m["data"].(map[string]any)
userMap := dataMap["user"].(map[string]any)
profileMap := userMap["profile"].(map[string]any)
if profileMap["name"] != "Charlie" {
t.Errorf("Expected 'Charlie', got '%v'", profileMap["name"])
}
})
t.Run("Get from nested map with all uppercase path", func(t *testing.T) {
m := map[string]any{
"company": map[string]any{
"department": map[string]any{
"name": "Engineering",
"employee": map[string]any{"count": 50},
},
},
}
rfx := New(&m)
// 使用全大写路径访问
name := rfx.Get("Company", "Department", "Name").String()
if name != "Engineering" {
t.Errorf("Expected 'Engineering', got '%s'", name)
}
count := rfx.Get("Company", "Department", "Employee", "Count").Int()
if count != 50 {
t.Errorf("Expected 50, got %d", count)
}
})
t.Run("Set creates nested structure with mixed case", func(t *testing.T) {
m := map[string]any{
"settings": map[string]any{},
}
rfx := New(&m)
// 设置嵌套值,使用大写键访问
rfx.Set("Settings.theme", "dark")
rfx.Set("Settings.language", "en")
settingsMap := m["settings"].(map[string]any)
if settingsMap["theme"] != "dark" {
t.Errorf("Expected 'dark', got '%v'", settingsMap["theme"])
}
if settingsMap["language"] != "en" {
t.Errorf("Expected 'en', got '%v'", settingsMap["language"])
}
})
}
// TestMapCaseInsensitiveWithStructs 测试 map 和 struct 混合时的大小写处理
func TestMapCaseInsensitiveWithStructs(t *testing.T) {
type Address struct {
City string
Street string
}
type User struct {
Name string
Age int
Address Address
}
t.Run("Struct embedded in map with case-insensitive access", func(t *testing.T) {
m := map[string]any{
"user": User{
Name: "Alice",
Age: 30,
Address: Address{
City: "Beijing",
Street: "Main St",
},
},
}
rfx := New(&m)
// 使用大写 User 访问小写 user 键
name := rfx.Get("User", "Name").String()
if name != "Alice" {
t.Errorf("Expected 'Alice', got '%s'", name)
}
city := rfx.Get("User", "Address", "City").String()
if city != "Beijing" {
t.Errorf("Expected 'Beijing', got '%s'", city)
}
})
t.Run("Set struct field through map with case-insensitive key (pointer)", func(t *testing.T) {
m := map[string]any{
"user": &User{
Name: "Alice",
Age: 30,
},
}
rfx := New(&m)
// 使用大写键路径设置 struct 字段(通过指针)
rfx.Set("User.Name", "Bob")
user := m["user"].(*User)
if user.Name != "Bob" {
t.Errorf("Expected 'Bob', got '%s'", user.Name)
}
})
t.Run("Map inside struct with case-insensitive access", func(t *testing.T) {
type Config struct {
Settings map[string]any
}
config := Config{
Settings: map[string]any{
"theme": "light",
"lang": "en",
},
}
rfx := New(&config)
// 使用大写键访问 map 中的小写键
theme := rfx.Get("Settings", "Theme").String()
if theme != "light" {
t.Errorf("Expected 'light', got '%s'", theme)
}
// 设置值
rfx.Set("Settings.Lang", "zh")
if config.Settings["lang"] != "zh" {
t.Errorf("Expected 'zh', got '%v'", config.Settings["lang"])
}
})
}
// TestMapCaseInsensitiveEdgeCases 测试大小写处理的边界情况
func TestMapCaseInsensitiveEdgeCases(t *testing.T) {
t.Run("Single character keys", func(t *testing.T) {
m := map[string]any{
"a": 1,
"b": 2,
}
rfx := New(&m)
// 使用大写访问小写
valA := rfx.Get("A").Int()
if valA != 1 {
t.Errorf("Expected 1, got %d", valA)
}
valB := rfx.Get("B").Int()
if valB != 2 {
t.Errorf("Expected 2, got %d", valB)
}
})
t.Run("Unicode characters in keys", func(t *testing.T) {
m := map[string]any{
"名字": "Alice",
"年龄": 30,
}
rfx := New(&m)
name := rfx.Get("名字").String()
if name != "Alice" {
t.Errorf("Expected 'Alice', got '%s'", name)
}
})
t.Run("Multiple nested maps with same key names", func(t *testing.T) {
m := map[string]any{
"level1": map[string]any{
"name": "L1",
"level2": map[string]any{
"name": "L2",
"level3": map[string]any{
"name": "L3",
},
},
},
}
rfx := New(&m)
// 使用大写路径访问
l1Name := rfx.Get("Level1", "Name").String()
if l1Name != "L1" {
t.Errorf("Expected 'L1', got '%s'", l1Name)
}
l2Name := rfx.Get("Level1", "Level2", "Name").String()
if l2Name != "L2" {
t.Errorf("Expected 'L2', got '%s'", l2Name)
}
l3Name := rfx.Get("Level1.Level2.Level3.Name").String()
if l3Name != "L3" {
t.Errorf("Expected 'L3', got '%s'", l3Name)
}
})
t.Run("Set value updates existing lowercase key", func(t *testing.T) {
m := map[string]any{
"config": map[string]any{
"timeout": 30,
"retry": 3,
},
}
rfx := New(&m)
// 使用大写键设置已存在的小写键
rfx.Set("Config.Timeout", 60)
rfx.Set("Config.Retry", 5)
configMap := m["config"].(map[string]any)
if configMap["timeout"] != 60 {
t.Errorf("Expected 60, got %v", configMap["timeout"])
}
if configMap["retry"] != 5 {
t.Errorf("Expected 5, got %v", configMap["retry"])
}
})
t.Run("Mixed case keys with numbers", func(t *testing.T) {
m := map[string]any{
"server1": map[string]any{"host": "localhost"},
"server2": map[string]any{"host": "example.com"},
}
rfx := New(&m)
host1 := rfx.Get("Server1", "Host").String()
if host1 != "localhost" {
t.Errorf("Expected 'localhost', got '%s'", host1)
}
host2 := rfx.Get("Server2.Host").String()
if host2 != "example.com" {
t.Errorf("Expected 'example.com', got '%s'", host2)
}
})
}
// TestMapCaseInsensitiveSetWithTypeConversion 测试设置值时的类型转换和大小写处理
func TestMapCaseInsensitiveSetWithTypeConversion(t *testing.T) {
t.Run("Set with type conversion on existing lowercase key", func(t *testing.T) {
m := map[string]any{
"config": map[string]int{
"timeout": 30,
},
}
rfx := New(&m)
// 使用大写键和字符串值设置 int 类型的 map
rfx.Set("Config.Timeout", "60")
configMap := m["config"].(map[string]int)
if configMap["timeout"] != 60 {
t.Errorf("Expected 60, got %v", configMap["timeout"])
}
})
t.Run("Set nested value with multiple type conversions", func(t *testing.T) {
m := map[string]any{
"data": map[string]any{
"stats": map[string]float64{
"rate": 0.5,
},
},
}
rfx := New(&m)
// 使用大写路径和整数值设置 float64
rfx.Set("Data.Stats.Rate", 100)
dataMap := m["data"].(map[string]any)
statsMap := dataMap["stats"].(map[string]float64)
if statsMap["rate"] != 100.0 {
t.Errorf("Expected 100.0, got %v", statsMap["rate"])
}
})
t.Run("Set with exact case match updates existing key", func(t *testing.T) {
m := map[string]any{
"user": map[string]any{
"name": "Alice",
},
}
rfx := New(&m)
// 使用大写键访问小写键,然后设置新字段
rfx.Set("User.age", 30)
// 验证在现有的小写键中添加了新字段
if userMap, ok := m["user"].(map[string]any); ok {
if userMap["age"] != 30 {
t.Errorf("Expected 30, got %v", userMap["age"])
}
} else {
t.Error("Expected 'user' key to contain the new field")
}
})
}