Files
reflux/rfx_nil_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

361 lines
7.9 KiB
Go

package reflux
import (
"testing"
)
// TestNewWithNilR 测试 New 接收包含 Nil 的 []R
func TestNewWithNilR(t *testing.T) {
t.Run("New with []R{Nil}", func(t *testing.T) {
r := New([]R{Nil})
arr := r.Array()
if len(arr) != 1 {
t.Fatalf("Expected Array() len 1, got %d", len(arr))
}
})
t.Run("Array element from []R{Nil} behaves as Nil", func(t *testing.T) {
r := New([]R{Nil})
elem := r.Array()[0]
if elem.Exists() {
t.Error("Expected Exists() to be false for Nil element")
}
if elem.Any() != nil {
t.Errorf("Expected Any() to be nil, got %v", elem.Any())
}
if elem.String() != "" {
t.Errorf("Expected String() to be empty, got %q", elem.String())
}
})
t.Run("New with []R{Nil} Slice()", func(t *testing.T) {
r := New([]R{Nil})
s := r.Slice()
if len(s) != 1 {
t.Fatalf("Expected Slice() len 1, got %d", len(s))
}
})
}
// TestSetValueWithNil 测试 setValue 方法处理 nil 值的各种情况
func TestSetValueWithNil(t *testing.T) {
t.Run("Set nil to pointer field", func(t *testing.T) {
type Data struct {
Ptr *string
}
data := Data{Ptr: stringPtr("initial")}
rfx := New(&data)
rfx.Set("Ptr", nil)
if data.Ptr != nil {
t.Errorf("Expected Ptr to be nil, got %v", data.Ptr)
}
})
t.Run("Set nil to interface field", func(t *testing.T) {
type Data struct {
Iface interface{}
}
data := Data{Iface: "initial"}
rfx := New(&data)
rfx.Set("Iface", nil)
if data.Iface != nil {
t.Errorf("Expected Iface to be nil, got %v", data.Iface)
}
})
t.Run("Set nil to slice field", func(t *testing.T) {
type Data struct {
Slice []string
}
data := Data{Slice: []string{"a", "b"}}
rfx := New(&data)
rfx.Set("Slice", nil)
if data.Slice != nil {
t.Errorf("Expected Slice to be nil, got %v", data.Slice)
}
})
t.Run("Set nil to map field", func(t *testing.T) {
type Data struct {
Map map[string]string
}
data := Data{Map: map[string]string{"key": "value"}}
rfx := New(&data)
rfx.Set("Map", nil)
if data.Map != nil {
t.Errorf("Expected Map to be nil, got %v", data.Map)
}
})
t.Run("Set nil to int field - should set to zero value", func(t *testing.T) {
type Data struct {
Value int
}
data := Data{Value: 42}
rfx := New(&data)
rfx.Set("Value", nil)
if data.Value != 0 {
t.Errorf("Expected Value to be 0, got %d", data.Value)
}
})
t.Run("Set nil to string field - should set to zero value", func(t *testing.T) {
type Data struct {
Value string
}
data := Data{Value: "hello"}
rfx := New(&data)
rfx.Set("Value", nil)
if data.Value != "" {
t.Errorf("Expected Value to be empty string, got %s", data.Value)
}
})
t.Run("Set nil to bool field - should set to zero value", func(t *testing.T) {
type Data struct {
Value bool
}
data := Data{Value: true}
rfx := New(&data)
rfx.Set("Value", nil)
if data.Value != false {
t.Errorf("Expected Value to be false, got %v", data.Value)
}
})
t.Run("Set nil to float64 field - should set to zero value", func(t *testing.T) {
type Data struct {
Value float64
}
data := Data{Value: 3.14}
rfx := New(&data)
rfx.Set("Value", nil)
if data.Value != 0.0 {
t.Errorf("Expected Value to be 0.0, got %f", data.Value)
}
})
t.Run("Set nil to uint field - should set to zero value", func(t *testing.T) {
type Data struct {
Value uint
}
data := Data{Value: 100}
rfx := New(&data)
rfx.Set("Value", nil)
if data.Value != 0 {
t.Errorf("Expected Value to be 0, got %d", data.Value)
}
})
t.Run("Set nil to nested pointer field", func(t *testing.T) {
type Inner struct {
Value string
}
type Outer struct {
Inner *Inner
}
data := Outer{Inner: &Inner{Value: "test"}}
rfx := New(&data)
rfx.Set("Inner", nil)
if data.Inner != nil {
t.Errorf("Expected Inner to be nil, got %v", data.Inner)
}
})
t.Run("Set nil in map", func(t *testing.T) {
m := map[string]interface{}{
"ptr": stringPtr("test"),
"slice": []int{1, 2, 3},
"map": map[string]string{"key": "value"},
}
rfx := New(&m)
rfx.Set("ptr", nil)
rfx.Set("slice", nil)
rfx.Set("map", nil)
if m["ptr"] != nil {
t.Errorf("Expected ptr to be nil, got %v", m["ptr"])
}
if m["slice"] != nil {
t.Errorf("Expected slice to be nil, got %v", m["slice"])
}
if m["map"] != nil {
t.Errorf("Expected map to be nil, got %v", m["map"])
}
})
t.Run("Set nil to various int types", func(t *testing.T) {
type Data struct {
Int8 int8
Int16 int16
Int32 int32
Int64 int64
Uint8 uint8
Uint16 uint16
Uint32 uint32
Uint64 uint64
}
data := Data{
Int8: 127,
Int16: 32767,
Int32: 2147483647,
Int64: 9223372036854775807,
Uint8: 255,
Uint16: 65535,
Uint32: 4294967295,
Uint64: 18446744073709551615,
}
rfx := New(&data)
rfx.Set("Int8", nil)
rfx.Set("Int16", nil)
rfx.Set("Int32", nil)
rfx.Set("Int64", nil)
rfx.Set("Uint8", nil)
rfx.Set("Uint16", nil)
rfx.Set("Uint32", nil)
rfx.Set("Uint64", nil)
if data.Int8 != 0 {
t.Errorf("Expected Int8 to be 0, got %d", data.Int8)
}
if data.Int16 != 0 {
t.Errorf("Expected Int16 to be 0, got %d", data.Int16)
}
if data.Int32 != 0 {
t.Errorf("Expected Int32 to be 0, got %d", data.Int32)
}
if data.Int64 != 0 {
t.Errorf("Expected Int64 to be 0, got %d", data.Int64)
}
if data.Uint8 != 0 {
t.Errorf("Expected Uint8 to be 0, got %d", data.Uint8)
}
if data.Uint16 != 0 {
t.Errorf("Expected Uint16 to be 0, got %d", data.Uint16)
}
if data.Uint32 != 0 {
t.Errorf("Expected Uint32 to be 0, got %d", data.Uint32)
}
if data.Uint64 != 0 {
t.Errorf("Expected Uint64 to be 0, got %d", data.Uint64)
}
})
t.Run("Set nil to float types", func(t *testing.T) {
type Data struct {
Float32 float32
Float64 float64
}
data := Data{
Float32: 3.14,
Float64: 2.718,
}
rfx := New(&data)
rfx.Set("Float32", nil)
rfx.Set("Float64", nil)
if data.Float32 != 0.0 {
t.Errorf("Expected Float32 to be 0.0, got %f", data.Float32)
}
if data.Float64 != 0.0 {
t.Errorf("Expected Float64 to be 0.0, got %f", data.Float64)
}
})
t.Run("Set nil to channel field", func(t *testing.T) {
type Data struct {
Chan chan int
}
ch := make(chan int)
data := Data{Chan: ch}
rfx := New(&data)
rfx.Set("Chan", nil)
if data.Chan != nil {
t.Errorf("Expected Chan to be nil, got %v", data.Chan)
}
})
t.Run("Set nil to func field", func(t *testing.T) {
type Data struct {
Func func()
}
data := Data{Func: func() {}}
rfx := New(&data)
rfx.Set("Func", nil)
if data.Func != nil {
t.Errorf("Expected Func to be nil")
}
})
t.Run("Set nil to nested struct with various types", func(t *testing.T) {
type Inner struct {
Ptr *string
Slice []int
Map map[string]string
Int int
String string
Bool bool
}
type Outer struct {
Inner Inner
}
data := Outer{
Inner: Inner{
Ptr: stringPtr("test"),
Slice: []int{1, 2, 3},
Map: map[string]string{"key": "value"},
Int: 42,
String: "hello",
Bool: true,
},
}
rfx := New(&data)
rfx.Set("Inner.Ptr", nil)
rfx.Set("Inner.Slice", nil)
rfx.Set("Inner.Map", nil)
rfx.Set("Inner.Int", nil)
rfx.Set("Inner.String", nil)
rfx.Set("Inner.Bool", nil)
if data.Inner.Ptr != nil {
t.Errorf("Expected Inner.Ptr to be nil, got %v", data.Inner.Ptr)
}
if data.Inner.Slice != nil {
t.Errorf("Expected Inner.Slice to be nil, got %v", data.Inner.Slice)
}
if data.Inner.Map != nil {
t.Errorf("Expected Inner.Map to be nil, got %v", data.Inner.Map)
}
if data.Inner.Int != 0 {
t.Errorf("Expected Inner.Int to be 0, got %d", data.Inner.Int)
}
if data.Inner.String != "" {
t.Errorf("Expected Inner.String to be empty, got %s", data.Inner.String)
}
if data.Inner.Bool != false {
t.Errorf("Expected Inner.Bool to be false, got %v", data.Inner.Bool)
}
})
}
// Helper function to create string pointer
func stringPtr(s string) *string {
return &s
}