Files
reflux/rfx_test.go
T
what 1f48635da3 fix: New()/Array() 正确处理 Nil 及已经是 R 的元素,不再 panic/重复包装
New(nil) 之前会 panic,现在返回 Nil(新增的 R 空实现单例,所有操作都是
安全的空操作/零值,不用调用方每次都判空)。New([]R{...}) 和 Array() 遇到
元素本身已经是 R(包括 Nil)时直接透传,不再重新拿 reflect.Value 包一层,
避免丢失原有的空值语义或类型信息。
2026-08-20 17:28:57 +08:00

1475 lines
34 KiB
Go

package reflux
import (
"encoding/json"
"reflect"
"testing"
"git.fsdpf.net/go/reflux/valuex"
)
// 测试用的结构体
type Person struct {
Name string
Age int
Email string
Address Address
Tags []string
Meta map[string]string
}
type Address struct {
City string
Street string
ZipCode int
}
// TestNew 测试 New 函数
func TestNew(t *testing.T) {
t.Run("New with pointer", func(t *testing.T) {
// 测试传入指针 - 修改应该影响原始数据
p := Person{Name: "Alice", Age: 30}
rfx := New(&p)
rfx.Set("Name", "Bob")
if p.Name != "Bob" {
t.Errorf("Expected original value to be modified, got '%s'", p.Name)
}
})
t.Run("New with value", func(t *testing.T) {
// 测试传入值 - 修改不应该影响原始数据
p := Person{Name: "Alice", Age: 30}
rfx := New(p)
rfx.Set("Name", "Bob")
// 原始值不应该被修改
if p.Name != "Alice" {
t.Errorf("Expected original value to remain 'Alice', got '%s'", p.Name)
}
// rfx 内部的值应该已经修改
if rfx.Get("Name").String() != "Bob" {
t.Errorf("Expected rfx value to be 'Bob', got '%s'", rfx.Get("Name").String())
}
})
t.Run("New with map pointer", func(t *testing.T) {
m := map[string]any{"name": "Alice"}
rfx := New(&m)
rfx.Set("name", "Bob")
if m["name"] != "Bob" {
t.Errorf("Expected map to be modified, got '%v'", m["name"])
}
})
t.Run("New with map value", func(t *testing.T) {
m := map[string]any{"name": "Alice"}
rfx := New(m)
rfx.Set("name", "Bob")
// 原始 map 不应该被修改
if m["name"] != "Alice" {
t.Errorf("Expected original map to remain 'Alice', got '%v'", m["name"])
}
})
t.Run("New with slice pointer", func(t *testing.T) {
s := []string{"a", "b", "c"}
rfx := New(&s)
rfx.Set("0", "x")
if s[0] != "x" {
t.Errorf("Expected slice to be modified, got '%s'", s[0])
}
})
t.Run("New with slice value", func(t *testing.T) {
s := []string{"a", "b", "c"}
rfx := New(s)
rfx.Set("0", "x")
// 原始切片不应该被修改
if s[0] != "a" {
t.Errorf("Expected original slice to remain 'a', got '%s'", s[0])
}
})
t.Run("New with array value", func(t *testing.T) {
a := [3]string{"a", "b", "c"}
rfx := New(a)
rfx.Set("0", "x")
// 原始数组不应该被修改
if a[0] != "a" {
t.Errorf("Expected original array to remain 'a', got '%s'", a[0])
}
})
t.Run("New with nil pointer", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("Expected panic with nil pointer")
}
}()
var p *Person
New(p)
})
t.Run("New with unsupported type", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("Expected panic with unsupported type")
}
}()
New(42) // int 不支持
})
t.Run("New with interface wrapping map", func(t *testing.T) {
// 测试 interface{} 包装的 map
var data any = map[string]string{"name": "Alice"}
rfx := New(data)
if rfx.Get("name").String() != "Alice" {
t.Errorf("Expected 'Alice', got '%s'", rfx.Get("name").String())
}
// 修改不应该影响原始数据(因为是值传递)
rfx.Set("name", "Bob")
originalMap := data.(map[string]string)
if originalMap["name"] != "Alice" {
t.Error("Original map should not be modified")
}
})
t.Run("New with interface wrapping struct", func(t *testing.T) {
// 测试 interface{} 包装的 struct
var data any = Person{Name: "Alice", Age: 30}
rfx := New(data)
if rfx.Get("Name").String() != "Alice" {
t.Errorf("Expected 'Alice', got '%s'", rfx.Get("Name").String())
}
})
t.Run("New with interface wrapping pointer", func(t *testing.T) {
// 测试 interface{} 包装的指针
person := Person{Name: "Alice", Age: 30}
var data any = &person
rfx := New(data)
rfx.Set("Name", "Bob")
// 原始数据应该被修改(因为是指针)
if person.Name != "Bob" {
t.Errorf("Expected original to be modified, got '%s'", person.Name)
}
})
t.Run("New with nil interface", func(t *testing.T) {
var data any
if New(data) != Nil {
t.Error("Expected Nil for nil interface")
}
})
}
// TestNewWithPointer 测试传入指针的情况
func TestNewWithPointer(t *testing.T) {
p := Person{Name: "Alice", Age: 30}
// 测试传入指针值
rfx := New(&p)
if rfx == nil {
t.Fatal("New() with pointer returned nil")
}
}
// TestGet 测试 Get 方法
func TestGet(t *testing.T) {
p := Person{
Name: "Bob",
Age: 25,
Address: Address{
City: "Beijing",
Street: "Main St",
},
Tags: []string{"developer", "gopher"},
}
rfx := New(&p)
// 测试获取顶层字段
name := rfx.Get("Name").String()
if name != "Bob" {
t.Errorf("Expected 'Bob', got '%s'", name)
}
// 测试获取嵌套字段
city := rfx.Get("Address", "City").String()
if city != "Beijing" {
t.Errorf("Expected 'Beijing', got '%s'", city)
}
// 测试获取切片元素
tag := rfx.Get("Tags", "0").String()
if tag != "developer" {
t.Errorf("Expected 'developer', got '%s'", tag)
}
}
// TestScope 测试 Scope 方法
func TestScope(t *testing.T) {
p := Person{
Address: Address{
City: "Shanghai",
Street: "Park Ave",
ZipCode: 200000,
},
}
rfx := New(&p)
addressScope := rfx.Scope("Address")
// 测试通过 Scope 获取值
city := addressScope.Get("City").String()
if city != "Shanghai" {
t.Errorf("Expected 'Shanghai', got '%s'", city)
}
// 测试通过 Scope 设置值后,原对象不应该被修改(因为是深度克隆)
addressScope.Set("City", "Beijing")
// 验证原对象的值没有改变(深度克隆)
if p.Address.City != "Shanghai" {
t.Errorf("Expected original object's City to remain 'Shanghai', got '%s'", p.Address.City)
}
// 验证 Scope 内的值已改变
scopeCity := addressScope.Get("City").String()
if scopeCity != "Beijing" {
t.Errorf("Expected scope's City to be 'Beijing', got '%s'", scopeCity)
}
// 验证通过原 rfx 对象获取的值仍然是原值
cityFromOriginal := rfx.Get("Address", "City").String()
if cityFromOriginal != "Shanghai" {
t.Errorf("Expected 'Shanghai' from original rfx, got '%s'", cityFromOriginal)
}
// 测试在 Scope 上设置多个字段
addressScope.Set("Street", "New Street").Set("ZipCode", 100000)
// 验证原对象的值都没有改变
if p.Address.Street != "Park Ave" {
t.Errorf("Expected original Street to remain 'Park Ave', got '%s'", p.Address.Street)
}
if p.Address.ZipCode != 200000 {
t.Errorf("Expected original ZipCode to remain 200000, got %d", p.Address.ZipCode)
}
// 验证 Scope 内的值已经改变
scopeStreet := addressScope.Get("Street").String()
scopeZipCode := addressScope.Get("ZipCode").Int()
if scopeStreet != "New Street" {
t.Errorf("Expected scope's Street to be 'New Street', got '%s'", scopeStreet)
}
if scopeZipCode != 100000 {
t.Errorf("Expected scope's ZipCode to be 100000, got %d", scopeZipCode)
}
// 再次验证 Scope 的值与原对象不同(证明是深度克隆)
if scopeCity == p.Address.City {
t.Error("Scope should have independent copy, not reference to original")
}
}
// TestSet 测试 Set 方法
func TestSet(t *testing.T) {
p := Person{
Name: "Charlie",
Age: 30,
Address: Address{
City: "Guangzhou",
},
Meta: make(map[string]string),
}
rfx := New(&p)
// 测试设置顶层字段
rfx.Set("Name", "David")
if p.Name != "David" {
t.Errorf("Expected 'David', got '%s'", p.Name)
}
// 测试设置嵌套字段
rfx.Set("Address.City", "Shenzhen")
if p.Address.City != "Shenzhen" {
t.Errorf("Expected 'Shenzhen', got '%s'", p.Address.City)
}
// 测试设置 map 值
rfx.Set("Meta.key1", "value1")
if p.Meta["key1"] != "value1" {
t.Errorf("Expected 'value1', got '%s'", p.Meta["key1"])
}
// 测试类型转换
rfx.Set("Age", int32(35))
if p.Age != 35 {
t.Errorf("Expected 35, got %d", p.Age)
}
// 测试设置整个 Address 结构体
newAddress := Address{
City: "Shanghai",
Street: "Nanjing Road",
ZipCode: 200000,
}
rfx.Set("Address", newAddress)
if p.Address.City != "Shanghai" {
t.Errorf("Expected City 'Shanghai', got '%s'", p.Address.City)
}
if p.Address.Street != "Nanjing Road" {
t.Errorf("Expected Street 'Nanjing Road', got '%s'", p.Address.Street)
}
if p.Address.ZipCode != 200000 {
t.Errorf("Expected ZipCode 200000, got %d", p.Address.ZipCode)
}
// 测试设置 Address 结构体后再修改其字段
rfx.Set("Address.ZipCode", 200001)
if p.Address.ZipCode != 200001 {
t.Errorf("Expected ZipCode 200001, got %d", p.Address.ZipCode)
}
}
// TestDelete 测试 Delete 方法
func TestDelete(t *testing.T) {
meta := map[string]string{
"key1": "value1",
"key2": "value2",
}
p := Person{
Meta: meta,
Tags: []string{"tag1", "tag2", "tag3"},
}
rfx := New(&p)
// 测试删除 map 键
rfx.Delete("Meta", "key1")
if _, exists := p.Meta["key1"]; exists {
t.Error("key1 should have been deleted")
}
// 测试删除切片元素
rfx.Delete("Tags", "1")
if len(p.Tags) != 2 || p.Tags[1] != "tag3" {
t.Errorf("Expected Tags to be ['tag1', 'tag3'], got %v", p.Tags)
}
}
// TestExists 测试 Exists 方法
func TestExists(t *testing.T) {
p := Person{
Name: "Eve",
Address: Address{
City: "Hangzhou",
},
}
rfx := New(&p)
// 测试存在的字段
if !rfx.Exists("Name") {
t.Error("Name should exist")
}
// 测试嵌套字段
if !rfx.Exists("Address", "City") {
t.Error("Address.City should exist")
}
// 测试不存在的字段
if rfx.Exists("NonExistent") {
t.Error("NonExistent should not exist")
}
// 测试空字段
if rfx.Exists("Email") {
// Email 是空字符串,但字段存在
email := rfx.Get("Email").String()
if email != "" {
t.Error("Email should be empty string")
}
}
}
// TestArray 测试 Array 方法
func TestArray(t *testing.T) {
tags := []string{"go", "rust", "python"}
p := Person{
Tags: tags,
}
rfx := New(&p)
arr := rfx.Get("Tags").Array()
if len(arr) != 3 {
t.Errorf("Expected array length 3, got %d", len(arr))
}
if arr[0].String() != "go" {
t.Errorf("Expected 'go', got '%s'", arr[0].String())
}
}
// TestKeys 测试 keys 方法
func TestKeys(t *testing.T) {
meta := map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}
p := Person{
Meta: meta,
}
rfx := New(&p)
keys := rfx.Get("Meta").Keys()
if len(keys) != 3 {
t.Errorf("Expected 3 keys, got %d", len(keys))
}
// 检查键是否存在
keyMap := make(map[string]bool)
for _, k := range keys {
keyMap[k] = true
}
if !keyMap["key1"] || !keyMap["key2"] || !keyMap["key3"] {
t.Error("Missing expected keys")
}
}
// TestTypeConversions 测试类型转换方法
func TestTypeConversions(t *testing.T) {
// 测试整数转换
type Numbers struct {
IntVal int
Int64Val int64
UintVal uint
FloatVal float64
BoolVal bool
StringVal string
}
n := Numbers{
IntVal: 42,
Int64Val: 9223372036854775807,
UintVal: 100,
FloatVal: 3.14,
BoolVal: true,
StringVal: "hello",
}
rfx := New(&n)
// Int
if rfx.Get("IntVal").Int() != 42 {
t.Error("Int() conversion failed")
}
// Int64
if rfx.Get("Int64Val").Int64() != 9223372036854775807 {
t.Error("Int64() conversion failed")
}
// Uint
if rfx.Get("UintVal").Uint() != 100 {
t.Error("Uint() conversion failed")
}
// Float64
if rfx.Get("FloatVal").Float64() != 3.14 {
t.Error("Float64() conversion failed")
}
// Bool
if !rfx.Get("BoolVal").Bool() {
t.Error("Bool() conversion failed")
}
// String
if rfx.Get("StringVal").String() != "hello" {
t.Error("String() conversion failed")
}
// 跨类型转换
if rfx.Get("IntVal").Float64() != 42.0 {
t.Error("Int to Float64 conversion failed")
}
if rfx.Get("FloatVal").Int64() != 3 {
t.Error("Float64 to Int64 conversion failed")
}
}
// TestStringMapConversions 测试 map 类型转换
func TestStringMapConversions(t *testing.T) {
type Maps struct {
StringMap map[string]string
IntMap map[string]int
BoolMap map[string]bool
StringSliceMap map[string][]string
}
m := Maps{
StringMap: map[string]string{
"name": "Alice",
"city": "NYC",
},
IntMap: map[string]int{
"age": 30,
"score": 100,
},
BoolMap: map[string]bool{
"active": true,
"enabled": false,
},
StringSliceMap: map[string][]string{
"tags": {"go", "rust"},
},
}
rfx := New(&m)
// StringMapString
strMap := rfx.Get("StringMap").StringMapString()
if strMap["name"] != "Alice" {
t.Error("StringMapString conversion failed")
}
// StringMapInt
intMap := rfx.Get("IntMap").StringMapInt()
if intMap["age"] != 30 {
t.Error("StringMapInt conversion failed")
}
// StringMapBool
boolMap := rfx.Get("BoolMap").StringMapBool()
if !boolMap["active"] {
t.Error("StringMapBool conversion failed")
}
// StringMapStringSlice
sliceMap := rfx.Get("StringSliceMap").StringMapStringSlice()
if len(sliceMap["tags"]) != 2 || sliceMap["tags"][0] != "go" {
t.Error("StringMapStringSlice conversion failed")
}
}
// TestSliceConversions 测试切片类型转换
func TestSliceConversions(t *testing.T) {
type Slices struct {
IntSlice []int
StringSlice []string
BoolSlice []bool
}
s := Slices{
IntSlice: []int{1, 2, 3},
StringSlice: []string{"a", "b", "c"},
BoolSlice: []bool{true, false, true},
}
rfx := New(&s)
// IntSlice
intSlice := rfx.Get("IntSlice").IntSlice()
if len(intSlice) != 3 || intSlice[1] != 2 {
t.Error("IntSlice conversion failed")
}
// StringSlice
strSlice := rfx.Get("StringSlice").StringSlice()
if len(strSlice) != 3 || strSlice[1] != "b" {
t.Error("StringSlice conversion failed")
}
// BoolSlice
boolSlice := rfx.Get("BoolSlice").BoolSlice()
if len(boolSlice) != 3 || boolSlice[1] != false {
t.Error("BoolSlice conversion failed")
}
// Slice (any)
anySlice := rfx.Get("IntSlice").Slice()
if len(anySlice) != 3 {
t.Error("Slice conversion failed")
}
}
// TestPtr 测试 Ptr 方法
func TestPtr(t *testing.T) {
p := Person{Name: "Frank"}
rfx := New(&p)
ptr := rfx.Ptr()
if ptr == nil {
t.Error("Ptr() returned nil")
}
// 验证指针指向正确的对象
if pPtr, ok := ptr.(*Person); ok {
if pPtr.Name != "Frank" {
t.Error("Ptr() returned incorrect pointer")
}
} else {
t.Error("Ptr() returned wrong type")
}
}
// TestGetPtrWithJSONUnmarshal 测试 Get().Ptr() 与 json.Unmarshal() 的配合
func TestGetPtrWithJSONUnmarshal(t *testing.T) {
t.Run("Unmarshal to nested struct field", func(t *testing.T) {
p := Person{
Name: "Alice",
Age: 30,
Address: Address{
City: "OldCity",
},
}
rfx := New(&p)
// 准备 JSON 数据
jsonData := []byte(`{
"City": "Shanghai",
"Street": "Nanjing Road",
"ZipCode": 200000
}`)
// 通过 Get().Ptr() 获取 Address 字段的指针
addressPtr := rfx.Get("Address").Ptr()
if addressPtr == nil {
t.Fatal("Get('Address').Ptr() returned nil")
}
// 使用 json.Unmarshal 直接赋值
err := json.Unmarshal(jsonData, addressPtr)
if err != nil {
t.Fatalf("json.Unmarshal failed: %v", err)
}
// 验证赋值成功
if p.Address.City != "Shanghai" {
t.Errorf("Expected City 'Shanghai', got '%s'", p.Address.City)
}
if p.Address.Street != "Nanjing Road" {
t.Errorf("Expected Street 'Nanjing Road', got '%s'", p.Address.Street)
}
if p.Address.ZipCode != 200000 {
t.Errorf("Expected ZipCode 200000, got %d", p.Address.ZipCode)
}
})
t.Run("Unmarshal to top-level struct", func(t *testing.T) {
p := Person{
Name: "Bob",
Age: 25,
}
rfx := New(&p)
// 准备 JSON 数据
jsonData := []byte(`{
"Name": "Charlie",
"Age": 35,
"Email": "charlie@example.com"
}`)
// 通过 Ptr() 获取整个 Person 的指针
personPtr := rfx.Ptr()
if personPtr == nil {
t.Fatal("Ptr() returned nil")
}
// 使用 json.Unmarshal 直接赋值
err := json.Unmarshal(jsonData, personPtr)
if err != nil {
t.Fatalf("json.Unmarshal failed: %v", err)
}
// 验证赋值成功
if p.Name != "Charlie" {
t.Errorf("Expected Name 'Charlie', got '%s'", p.Name)
}
if p.Age != 35 {
t.Errorf("Expected Age 35, got %d", p.Age)
}
if p.Email != "charlie@example.com" {
t.Errorf("Expected Email 'charlie@example.com', got '%s'", p.Email)
}
})
t.Run("Unmarshal to map field", func(t *testing.T) {
p := Person{
Name: "Dave",
Meta: make(map[string]string),
}
rfx := New(&p)
// 准备 JSON 数据
jsonData := []byte(`{
"key1": "value1",
"key2": "value2",
"key3": "value3"
}`)
// 通过 Get().Ptr() 获取 Meta 字段的指针
metaPtr := rfx.Get("Meta").Ptr()
if metaPtr == nil {
t.Fatal("Get('Meta').Ptr() returned nil")
}
// 使用 json.Unmarshal 直接赋值
err := json.Unmarshal(jsonData, metaPtr)
if err != nil {
t.Fatalf("json.Unmarshal failed: %v", err)
}
// 验证赋值成功
if p.Meta["key1"] != "value1" {
t.Errorf("Expected Meta['key1'] 'value1', got '%s'", p.Meta["key1"])
}
if p.Meta["key2"] != "value2" {
t.Errorf("Expected Meta['key2'] 'value2', got '%s'", p.Meta["key2"])
}
if p.Meta["key3"] != "value3" {
t.Errorf("Expected Meta['key3'] 'value3', got '%s'", p.Meta["key3"])
}
})
t.Run("Unmarshal to slice field", func(t *testing.T) {
p := Person{
Name: "Eve",
Tags: []string{"old1", "old2"},
}
rfx := New(&p)
// 准备 JSON 数据
jsonData := []byte(`["tag1", "tag2", "tag3"]`)
// 通过 Get().Ptr() 获取 Tags 字段的指针
tagsPtr := rfx.Get("Tags").Ptr()
if tagsPtr == nil {
t.Fatal("Get('Tags').Ptr() returned nil")
}
// 使用 json.Unmarshal 直接赋值
err := json.Unmarshal(jsonData, tagsPtr)
if err != nil {
t.Fatalf("json.Unmarshal failed: %v", err)
}
// 验证赋值成功
if len(p.Tags) != 3 {
t.Errorf("Expected Tags length 3, got %d", len(p.Tags))
}
if p.Tags[0] != "tag1" || p.Tags[1] != "tag2" || p.Tags[2] != "tag3" {
t.Errorf("Expected Tags ['tag1', 'tag2', 'tag3'], got %v", p.Tags)
}
})
}
// TestAny 测试 Any 方法
func TestAny(t *testing.T) {
p := Person{Name: "Grace", Age: 28}
rfx := New(&p)
anyVal := rfx.Any()
if person, ok := anyVal.(Person); ok {
if person.Name != "Grace" || person.Age != 28 {
t.Error("Any() returned incorrect value")
}
} else {
t.Error("Any() returned wrong type")
}
}
// TestRaw 测试 Value 方法
func TestRaw(t *testing.T) {
p := Person{Name: "Henry"}
rfx := New(&p)
val := rfx.Raw()
if !val.IsValid() {
t.Error("Value() returned invalid value")
}
if val.Kind() != 22 { // reflect.Ptr
t.Errorf("Expected pointer kind, got %v", val.Kind())
}
}
// TestComplexNesting 测试复杂嵌套场景
func TestComplexNesting(t *testing.T) {
type Company struct {
Name string
Employees []Person
}
company := Company{
Name: "TechCorp",
Employees: []Person{
{Name: "Alice", Age: 30},
{Name: "Bob", Age: 25},
},
}
rfx := New(&company)
// 获取嵌套数组中的值
empName := rfx.Get("Employees", "0", "Name").String()
if empName != "Alice" {
t.Errorf("Expected 'Alice', got '%s'", empName)
}
// 设置嵌套数组中的值
rfx.Set("Employees.0.Age", 31)
if company.Employees[0].Age != 31 {
t.Errorf("Expected 31, got %d", company.Employees[0].Age)
}
}
// TestEdgeCases 测试边界情况
func TestEdgeCases(t *testing.T) {
p := Person{}
rfx := New(&p)
// 测试空值
emptyStr := rfx.Get("Name").String()
if emptyStr != "" {
t.Error("Empty string should be returned")
}
// 测试不存在的路径
nonExistent := rfx.Get("NonExistent", "Field").String()
if nonExistent != "" {
t.Error("Non-existent path should return empty string")
}
// 测试初始化的 nil map(结构体字段默认为 nil)
metaMap := rfx.Get("Meta").StringMapString()
// nil map 会返回 nil,这是正确的行为
_ = metaMap
// 测试 nil 切片(结构体字段默认为 nil)
tags := rfx.Get("Tags").StringSlice()
// nil slice 会返回 nil,这是正确的行为
_ = tags
// 测试设置到不存在的路径应该 panic
defer func() {
if r := recover(); r == nil {
t.Error("Setting non-existent field should panic")
}
}()
rfx.Set("NonExistent", "value") // 应该 panic
}
// TestMapOperations 测试 map 操作
func TestMapOperations(t *testing.T) {
m := map[string]any{
"name": "Alice",
"age": 30,
"tags": []string{"go", "rust"},
}
rfx := New(&m)
// Get from map
name := rfx.Get("name").String()
if name != "Alice" {
t.Errorf("Expected 'Alice', got '%s'", name)
}
// Set to map
rfx.Set("name", "Bob")
if m["name"] != "Bob" {
t.Errorf("Expected 'Bob', got '%v'", m["name"])
}
// Add new key
rfx.Set("age", 35)
// Delete from map
rfx.Delete("age")
if _, exists := m["age"]; exists {
t.Error("Key should have been deleted")
}
}
// BenchmarkGet 性能测试 Get 方法
func BenchmarkGet(b *testing.B) {
p := Person{
Name: "Benchmark",
Address: Address{
City: "TestCity",
},
}
rfx := New(&p)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = rfx.Get("Address", "City").String()
}
}
// BenchmarkSet 性能测试 Set 方法
func BenchmarkSet(b *testing.B) {
p := Person{}
rfx := New(&p)
b.ResetTimer()
for i := 0; i < b.N; i++ {
rfx.Set("Name", "TestName")
}
}
// TestDotNotationPath 测试点号分割路径
func TestDotNotationPath(t *testing.T) {
p := Person{
Name: "Alice",
Age: 30,
Address: Address{
City: "Beijing",
Street: "Main St",
ZipCode: 100000,
},
Tags: []string{"go", "rust", "python"},
Meta: map[string]string{
"level": "senior",
},
}
rfx := New(&p)
// 测试点号分割路径获取
t.Run("Get with dot notation", func(t *testing.T) {
// 使用点号访问嵌套字段
city := rfx.Get("Address.City").String()
if city != "Beijing" {
t.Errorf("Expected 'Beijing', got '%s'", city)
}
zipCode := rfx.Get("Address.ZipCode").Int()
if zipCode != 100000 {
t.Errorf("Expected 100000, got %d", zipCode)
}
})
// 测试混合使用点号和分隔参数
t.Run("Get with mixed notation", func(t *testing.T) {
city := rfx.Get("Address.City").String()
if city != "Beijing" {
t.Errorf("Expected 'Beijing', got '%s'", city)
}
// 混合使用
metaLevel := rfx.Get("Meta", "level").String()
if metaLevel != "senior" {
t.Errorf("Expected 'senior', got '%s'", metaLevel)
}
// 也可以用点号访问 Map
metaLevel2 := rfx.Get("Meta.level").String()
if metaLevel2 != "senior" {
t.Errorf("Expected 'senior', got '%s'", metaLevel2)
}
})
// 测试访问切片元素
t.Run("Get array with dot notation", func(t *testing.T) {
tag := rfx.Get("Tags.0").String()
if tag != "go" {
t.Errorf("Expected 'go', got '%s'", tag)
}
tag2 := rfx.Get("Tags.1").String()
if tag2 != "rust" {
t.Errorf("Expected 'rust', got '%s'", tag2)
}
})
// 测试 Set 使用点号路径
t.Run("Set with dot notation", func(t *testing.T) {
rfx.Set("Address.City", "Shanghai")
if p.Address.City != "Shanghai" {
t.Errorf("Expected 'Shanghai', got '%s'", p.Address.City)
}
rfx.Set("Address.ZipCode", 200000)
if p.Address.ZipCode != 200000 {
t.Errorf("Expected 200000, got %d", p.Address.ZipCode)
}
})
// 测试 Exists 使用点号路径
t.Run("Exists with dot notation", func(t *testing.T) {
if !rfx.Exists("Address.City") {
t.Error("Address.City should exist")
}
if rfx.Exists("Address.NonExistent") {
t.Error("Address.NonExistent should not exist")
}
})
// 测试 Delete 使用点号路径
t.Run("Delete with dot notation", func(t *testing.T) {
rfx.Delete("Meta.level")
if _, exists := p.Meta["level"]; exists {
t.Error("Meta.level should have been deleted")
}
})
// 测试 Scope 使用点号路径
t.Run("Scope with dot notation", func(t *testing.T) {
addressScope := rfx.Scope("Address")
city := addressScope.Get("City").String()
if city != "Shanghai" {
t.Errorf("Expected 'Shanghai', got '%s'", city)
}
})
}
// TestExpandPath 测试路径展开功能
func TestExpandPath(t *testing.T) {
tests := []struct {
name string
input []string
expected []string
}{
{
name: "Simple path",
input: []string{"a", "b", "c"},
expected: []string{"a", "b", "c"},
},
{
name: "Dot notation",
input: []string{"a.b.c"},
expected: []string{"a", "b", "c"},
},
{
name: "Mixed notation",
input: []string{"a.b", "c"},
expected: []string{"a", "b", "c"},
},
{
name: "Multiple dots",
input: []string{"a.b", "c.d", "e"},
expected: []string{"a", "b", "c", "d", "e"},
},
{
name: "Empty segments",
input: []string{"a..b", "c"},
expected: []string{"a", "b", "c"},
},
{
name: "Leading/trailing dots",
input: []string{".a.b.", "c"},
expected: []string{"a", "b", "c"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := expandPath(tt.input...)
if len(result) != len(tt.expected) {
t.Errorf("Expected length %d, got %d", len(tt.expected), len(result))
return
}
for i := range result {
if result[i] != tt.expected[i] {
t.Errorf("At index %d: expected '%s', got '%s'", i, tt.expected[i], result[i])
}
}
})
}
}
// TestComplexDotNotation 测试复杂的点号路径场景
func TestComplexDotNotation(t *testing.T) {
type Company struct {
Name string
Address Address
CEO Person
}
company := Company{
Name: "TechCorp",
Address: Address{
City: "Beijing",
Street: "Tech Street",
},
CEO: Person{
Name: "John Doe",
Age: 45,
Address: Address{
City: "Shanghai",
},
},
}
rfx := New(&company)
// 深层嵌套访问
ceoCity := rfx.Get("CEO.Address.City").String()
if ceoCity != "Shanghai" {
t.Errorf("Expected 'Shanghai', got '%s'", ceoCity)
}
// 设置深层嵌套值
rfx.Set("CEO.Address.City", "Guangzhou")
if company.CEO.Address.City != "Guangzhou" {
t.Errorf("Expected 'Guangzhou', got '%s'", company.CEO.Address.City)
}
// 检查深层路径存在性
if !rfx.Exists("CEO.Address.City") {
t.Error("CEO.Address.City should exist")
}
}
// TestScopeSetIssue 测试 Scope 深度克隆的特性
func TestScopeSetIssue(t *testing.T) {
p := Person{
Name: "Alice",
Address: Address{
City: "Beijing",
},
}
rfx := New(&p)
// 测试直接通过路径设置值 - 这应该可以工作
t.Run("Direct path set", func(t *testing.T) {
rfx.Set("Address.City", "Shanghai")
if p.Address.City != "Shanghai" {
t.Errorf("Expected 'Shanghai', got '%s'", p.Address.City)
}
})
// 测试通过 Scope 设置值 - 由于是深度克隆,不会修改原始值
t.Run("Scope set - deep clone behavior", func(t *testing.T) {
addressScope := rfx.Scope("Address")
originalCity := p.Address.City // "Shanghai"
// 在 Scope 上设置值
addressScope.Set("City", "Guangzhou")
// 原始值不应该被修改(因为 Scope 返回深度克隆)
if p.Address.City != originalCity {
t.Errorf("Original value should remain '%s', got '%s'", originalCity, p.Address.City)
}
// Scope 内的值应该已经改变
scopeCity := addressScope.Get("City").String()
if scopeCity != "Guangzhou" {
t.Errorf("Scope value should be 'Guangzhou', got '%s'", scopeCity)
}
})
// 测试获取 Scope 的值是独立副本
t.Run("Scope returns independent copy", func(t *testing.T) {
// 获取 Address 的 Scope
addressScope := rfx.Scope("Address")
// 获取 Scope 的 Any 值
addr := addressScope.Any()
if address, ok := addr.(Address); ok {
originalCity := p.Address.City
// 修改 Scope 返回的值
addressScope.Set("City", "TestCity")
// 原始值不应该被修改
if p.Address.City != originalCity {
t.Errorf("Modifying scope should not affect original, expected '%s', got '%s'",
originalCity, p.Address.City)
}
// 确保 address 变量本身也是副本
_ = address
}
})
// 测试嵌套 Scope 的深度克隆
t.Run("Nested scope deep clone", func(t *testing.T) {
p2 := Person{
Name: "Bob",
Age: 25,
Address: Address{
City: "Beijing",
Street: "Main St",
ZipCode: 100000,
},
}
sm2 := New(&p2)
// 创建 Scope
scope := sm2.Scope("Address")
// 在 Scope 上修改多个字段
scope.Set("City", "Shenzhen")
scope.Set("Street", "New Street")
scope.Set("ZipCode", 518000)
// 验证原始对象没有被修改
if p2.Address.City != "Beijing" {
t.Errorf("Original City should be 'Beijing', got '%s'", p2.Address.City)
}
if p2.Address.Street != "Main St" {
t.Errorf("Original Street should be 'Main St', got '%s'", p2.Address.Street)
}
if p2.Address.ZipCode != 100000 {
t.Errorf("Original ZipCode should be 100000, got %d", p2.Address.ZipCode)
}
// 验证 Scope 内的值已改变
if scope.Get("City").String() != "Shenzhen" {
t.Errorf("Scope City should be 'Shenzhen', got '%s'", scope.Get("City").String())
}
})
}
// TestScopeDeepClone 测试 Scope 深度克隆复杂嵌套结构
func TestScopeDeepClone(t *testing.T) {
type Company struct {
Name string
Employees []Person
Locations map[string]Address
}
company := Company{
Name: "TechCorp",
Employees: []Person{
{
Name: "Alice",
Age: 30,
Address: Address{
City: "Beijing",
Street: "Main St",
},
Tags: []string{"go", "rust"},
},
{
Name: "Bob",
Age: 25,
Address: Address{
City: "Shanghai",
},
},
},
Locations: map[string]Address{
"hq": {
City: "Beijing",
Street: "Tech Park",
ZipCode: 100000,
},
},
}
rfx := New(&company)
t.Run("Clone and modify nested slice", func(t *testing.T) {
// 创建 Employees 的 Scope
empScope := rfx.Scope("Employees")
// 修改 Scope 中的值
empScope.Set("0.Name", "Charlie")
empScope.Set("0.Age", 35)
// 验证原始数据没有被修改
if company.Employees[0].Name != "Alice" {
t.Errorf("Original employee name should be 'Alice', got '%s'", company.Employees[0].Name)
}
if company.Employees[0].Age != 30 {
t.Errorf("Original employee age should be 30, got %d", company.Employees[0].Age)
}
// 验证 Scope 中的值已修改
if empScope.Get("0", "Name").String() != "Charlie" {
t.Error("Scope employee name should be 'Charlie'")
}
})
t.Run("Clone and modify nested map", func(t *testing.T) {
// 创建 Locations 的 Scope
locScope := rfx.Scope("Locations")
// 修改 Scope 中的值
locScope.Set("hq.City", "Shanghai").Set("hq.ZipCode", 200000)
// 验证原始数据没有被修改
if company.Locations["hq"].City != "Beijing" {
t.Errorf("Original location city should be 'Beijing', got '%s'", company.Locations["hq"].City)
}
if company.Locations["hq"].ZipCode != 100000 {
t.Errorf("Original location zipcode should be 100000, got %d", company.Locations["hq"].ZipCode)
}
// 验证 Scope 中的值已修改
if locScope.Get("hq", "City").String() != "Shanghai" {
t.Error("Scope location city should be 'Shanghai'")
}
if locScope.Get("hq", "ZipCode").Int() != 200000 {
t.Error("Scope location zipcode should be 200000")
}
})
t.Run("Clone nested struct with slices", func(t *testing.T) {
// 创建第一个员工的 Scope
emp0Scope := rfx.Scope("Employees", "0")
// 修改嵌套的切片
emp0Scope.Set("Tags.0", "python")
// 验证原始数据没有被修改
if company.Employees[0].Tags[0] != "go" {
t.Errorf("Original tag should be 'go', got '%s'", company.Employees[0].Tags[0])
}
// 验证 Scope 中的值已修改
if emp0Scope.Get("Tags", "0").String() != "python" {
t.Error("Scope tag should be 'python'")
}
})
}
// TestSetValueWithCastInStruct 测试在实际结构体中使用 cast 转换
func TestSetValueWithCastInStruct(t *testing.T) {
type Config struct {
Port int
Host string
Enabled bool
Timeout float64
}
config := Config{}
rfx := New(&config)
// 字符串转 int
rfx.Set("Port", "8080")
if config.Port != 8080 {
t.Errorf("Expected Port to be 8080, got %d", config.Port)
}
// int 转 string
rfx.Set("Host", 12345)
if config.Host != "12345" {
t.Errorf("Expected Host to be '12345', got '%s'", config.Host)
}
// 字符串转 bool
rfx.Set("Enabled", "true")
if !config.Enabled {
t.Errorf("Expected Enabled to be true, got %v", config.Enabled)
}
// 字符串转 float
rfx.Set("Timeout", "30.5")
if config.Timeout != 30.5 {
t.Errorf("Expected Timeout to be 30.5, got %f", config.Timeout)
}
}
// TestSetValueChainWithCast 测试链式调用中的 cast 转换
func TestSetValueChainWithCast(t *testing.T) {
type User struct {
Name string
Age int
Active bool
Score float64
}
user := User{}
rfx := New(&user)
// 链式设置,使用不同类型的值
rfx.Set("Name", 12345). // int -> string
Set("Age", "30"). // string -> int
Set("Active", "1"). // string -> bool
Set("Score", "95.5") // string -> float64
if user.Name != "12345" {
t.Errorf("Expected Name to be '12345', got '%s'", user.Name)
}
if user.Age != 30 {
t.Errorf("Expected Age to be 30, got %d", user.Age)
}
if !user.Active {
t.Errorf("Expected Active to be true, got %v", user.Active)
}
if user.Score != 95.5 {
t.Errorf("Expected Score to be 95.5, got %f", user.Score)
}
}
// TestNormalizeValuexAccessor 测试 normalizeInputValue 对 valuex.Accessor 的支持
func TestNormalizeValuexAccessor(t *testing.T) {
// 创建一个 R 实例
data := map[string]any{
"name": "Alice",
"age": 30,
}
r := New(data)
// 测试 valuex.Accessor 类型
rv, isPtr, err := normalizeInputValue(r)
if err != nil {
t.Fatalf("normalizeInputValue failed: %v", err)
}
if !isPtr {
t.Error("Expected isPtr to be true for valuex.Accessor")
}
if !rv.IsValid() {
t.Error("Expected valid reflect.Value")
}
}
// TestNormalizeValuexAccessorSlice 测试 normalizeInputValue 对 []valuex.Accessor 的支持
func TestNormalizeValuexAccessorSlice(t *testing.T) {
// 创建多个 R 实例
r1 := New(map[string]any{"id": 1, "name": "Alice"})
r2 := New(map[string]any{"id": 2, "name": "Bob"})
// 创建 []valuex.Accessor
slice := []valuex.Accessor{r1, r2}
// 测试 []valuex.Accessor 类型
rv, isPtr, err := normalizeInputValue(slice)
if err != nil {
t.Fatalf("normalizeInputValue failed: %v", err)
}
if !isPtr {
t.Error("Expected isPtr to be true for []valuex.Accessor")
}
if !rv.IsValid() {
t.Error("Expected valid reflect.Value")
}
if rv.Kind() != reflect.Slice {
t.Errorf("Expected Slice kind, got %v", rv.Kind())
}
if rv.Len() != 2 {
t.Errorf("Expected slice length 2, got %d", rv.Len())
}
}