增强 setValue 函数,支持将 R 接口包装的指针值追加到非指针类型的切片中。当源值是指针但目标不是指针时,自动解引用后再赋值,使得 New(&item) 可以追加到 []Item 类型的切片。同时统一使用 Raw() 方法替代 Value() 方法名。
248 lines
5.5 KiB
Go
248 lines
5.5 KiB
Go
package reflux
|
||
|
||
import (
|
||
"testing"
|
||
)
|
||
|
||
// TestAppendWithRInterface 测试 Append 方法对 R 接口的支持
|
||
func TestAppendWithRInterface(t *testing.T) {
|
||
t.Run("Append R interface to slice", func(t *testing.T) {
|
||
type Item struct {
|
||
Name string
|
||
Value int
|
||
}
|
||
|
||
items := []Item{}
|
||
rfx := New(&items)
|
||
|
||
// 创建 R 实例
|
||
item1 := Item{Name: "apple", Value: 10}
|
||
r1 := New(&item1)
|
||
|
||
item2 := Item{Name: "banana", Value: 20}
|
||
r2 := New(item2)
|
||
|
||
// 使用 Append 添加 R 接口
|
||
rfx.Append(r1, r2)
|
||
|
||
if len(items) != 2 {
|
||
t.Fatalf("Expected 2 items, got %d", len(items))
|
||
}
|
||
|
||
if items[0].Name != "apple" || items[0].Value != 10 {
|
||
t.Errorf("Item[0] mismatch: got %+v", items[0])
|
||
}
|
||
|
||
if items[1].Name != "banana" || items[1].Value != 20 {
|
||
t.Errorf("Item[1] mismatch: got %+v", items[1])
|
||
}
|
||
})
|
||
|
||
t.Run("Append mixed types including R interface", func(t *testing.T) {
|
||
type Number struct {
|
||
Value int
|
||
}
|
||
|
||
numbers := []int{}
|
||
rfx := New(&numbers)
|
||
|
||
// 创建 R 实例包装 map(使用 map 代替基本类型)
|
||
numMap := map[string]int{"value": 42}
|
||
rNum := New(&numMap)
|
||
|
||
// 混合添加普通值和通过 Get 提取的值
|
||
rfx.Append(10, rNum.Get("value").Int(), 30)
|
||
|
||
if len(numbers) != 3 {
|
||
t.Fatalf("Expected 3 numbers, got %d", len(numbers))
|
||
}
|
||
|
||
if numbers[0] != 10 || numbers[1] != 42 || numbers[2] != 30 {
|
||
t.Errorf("Numbers mismatch: got %v", numbers)
|
||
}
|
||
})
|
||
|
||
t.Run("Append with nested R interface", func(t *testing.T) {
|
||
type Address struct {
|
||
City string
|
||
}
|
||
|
||
addresses := []Address{}
|
||
rfx := New(&addresses)
|
||
|
||
// 创建嵌套的 R 实例
|
||
addr := Address{City: "Beijing"}
|
||
rAddr := New(&addr)
|
||
|
||
rfx.Append(rAddr)
|
||
|
||
if len(addresses) != 1 {
|
||
t.Fatalf("Expected 1 address, got %d", len(addresses))
|
||
}
|
||
|
||
if addresses[0].City != "Beijing" {
|
||
t.Errorf("Expected City=Beijing, got %s", addresses[0].City)
|
||
}
|
||
})
|
||
|
||
t.Run("Append map through R interface", func(t *testing.T) {
|
||
type Config map[string]string
|
||
|
||
configs := []Config{}
|
||
rfx := New(&configs)
|
||
|
||
// 创建 map 的 R 实例
|
||
cfg := Config{"host": "localhost", "port": "8080"}
|
||
rCfg := New(&cfg)
|
||
|
||
rfx.Append(rCfg)
|
||
|
||
if len(configs) != 1 {
|
||
t.Fatalf("Expected 1 config, got %d", len(configs))
|
||
}
|
||
|
||
if configs[0]["host"] != "localhost" || configs[0]["port"] != "8080" {
|
||
t.Errorf("Config mismatch: got %+v", configs[0])
|
||
}
|
||
})
|
||
}
|
||
|
||
// TestSetWithAutoInit 测试 Set 方法的自动初始化功能
|
||
func TestSetWithAutoInit(t *testing.T) {
|
||
t.Run("Auto init nil map", func(t *testing.T) {
|
||
type Container struct {
|
||
Data map[string]string
|
||
}
|
||
|
||
container := Container{}
|
||
rfx := New(&container)
|
||
|
||
// 设置 nil map 的值,应该自动初始化
|
||
rfx.Set("Data.key1", "value1")
|
||
rfx.Set("Data.key2", "value2")
|
||
|
||
if container.Data == nil {
|
||
t.Fatal("Expected Data to be initialized, got nil")
|
||
}
|
||
|
||
if container.Data["key1"] != "value1" {
|
||
t.Errorf("Expected key1=value1, got %s", container.Data["key1"])
|
||
}
|
||
|
||
if container.Data["key2"] != "value2" {
|
||
t.Errorf("Expected key2=value2, got %s", container.Data["key2"])
|
||
}
|
||
})
|
||
|
||
t.Run("Auto init nested nil map", func(t *testing.T) {
|
||
type Nested struct {
|
||
Meta map[string]any
|
||
}
|
||
|
||
type Root struct {
|
||
Config Nested
|
||
}
|
||
|
||
root := Root{}
|
||
rfx := New(&root)
|
||
|
||
// 设置嵌套的 nil map
|
||
rfx.Set("Config.Meta.host", "localhost")
|
||
rfx.Set("Config.Meta.port", 8080)
|
||
|
||
if root.Config.Meta == nil {
|
||
t.Fatal("Expected Meta to be initialized, got nil")
|
||
}
|
||
|
||
if root.Config.Meta["host"] != "localhost" {
|
||
t.Errorf("Expected host=localhost, got %v", root.Config.Meta["host"])
|
||
}
|
||
|
||
if root.Config.Meta["port"] != 8080 {
|
||
t.Errorf("Expected port=8080, got %v", root.Config.Meta["port"])
|
||
}
|
||
})
|
||
|
||
t.Run("Auto init map with R interface value", func(t *testing.T) {
|
||
type Settings struct {
|
||
Options map[string]int
|
||
}
|
||
|
||
settings := Settings{}
|
||
rfx := New(&settings)
|
||
|
||
// 使用 R 接口包装的值(使用 map 而非基本类型)
|
||
timeoutData := map[string]int{"value": 30}
|
||
rTimeout := New(&timeoutData)
|
||
|
||
// 通过 Get 提取值再设置
|
||
rfx.Set("Options.timeout", rTimeout.Get("value").Int())
|
||
|
||
if settings.Options == nil {
|
||
t.Fatal("Expected Options to be initialized, got nil")
|
||
}
|
||
|
||
if settings.Options["timeout"] != 30 {
|
||
t.Errorf("Expected timeout=30, got %d", settings.Options["timeout"])
|
||
}
|
||
})
|
||
|
||
t.Run("Set to uninitialized map in nested structure", func(t *testing.T) {
|
||
type Database struct {
|
||
Params map[string]string
|
||
}
|
||
|
||
type Config struct {
|
||
DB Database
|
||
}
|
||
|
||
config := Config{
|
||
DB: Database{}, // Params is nil
|
||
}
|
||
|
||
rfx := New(&config)
|
||
|
||
// 设置未初始化的 map
|
||
rfx.Set("DB.Params.host", "localhost")
|
||
rfx.Set("DB.Params.port", "5432")
|
||
|
||
if config.DB.Params == nil {
|
||
t.Fatal("Expected Params to be initialized, got nil")
|
||
}
|
||
|
||
if config.DB.Params["host"] != "localhost" {
|
||
t.Errorf("Expected host=localhost, got %s", config.DB.Params["host"])
|
||
}
|
||
|
||
if config.DB.Params["port"] != "5432" {
|
||
t.Errorf("Expected port=5432, got %s", config.DB.Params["port"])
|
||
}
|
||
})
|
||
|
||
t.Run("Set complex value to auto-initialized map", func(t *testing.T) {
|
||
type Item struct {
|
||
Name string
|
||
Count int
|
||
}
|
||
|
||
type Store struct {
|
||
Items map[string]Item
|
||
}
|
||
|
||
store := Store{}
|
||
rfx := New(&store)
|
||
|
||
// 设置复杂类型到未初始化的 map
|
||
item := Item{Name: "apple", Count: 10}
|
||
rfx.Set("Items.fruit", item)
|
||
|
||
if store.Items == nil {
|
||
t.Fatal("Expected Items to be initialized, got nil")
|
||
}
|
||
|
||
if store.Items["fruit"].Name != "apple" || store.Items["fruit"].Count != 10 {
|
||
t.Errorf("Expected Item{Name:apple, Count:10}, got %+v", store.Items["fruit"])
|
||
}
|
||
})
|
||
}
|