package convert_test import ( "reflect" "testing" "apigo.cc/go/convert" ) // Matrix Test Entry func TestConvertMatrix(t *testing.T) { type testCase struct { name string from any to any // 传入指针的指针,用于接收结果 expected any } // 1. 基础类型全互转矩阵 cases := []testCase{ {name: "int to string", from: 123, to: new(string), expected: "123"}, {name: "string to int", from: "456", to: new(int), expected: 456}, {name: "float to int", from: 123.45, to: new(int), expected: 123}, {name: "bool to string", from: true, to: new(string), expected: "true"}, {name: "string to bool", from: "1", to: new(bool), expected: true}, {name: "string to bool (text)", from: "true", to: new(bool), expected: true}, // 2. 容器与单值的自动包装/解包 (去摩擦) {name: "single to slice", from: 100, to: new([]int), expected: []int{100}}, {name: "slice to single (len 1)", from: []int{200}, to: new(int), expected: 200}, {name: "slice to single (len >1, take first)", from: []int{300, 400}, to: new(int), expected: 300}, // 3. 字符串与切片的智能转换 {name: "csv string to slice", from: "1, 2, 3", to: new([]int), expected: []int{1, 2, 3}}, {name: "json string to slice", from: `[4, 5, 6]`, to: new([]int), expected: []int{4, 5, 6}}, // 4. 指针转换 (深度穿透) {name: "deep pointer to val", from: ptr(ptr(789)), to: new(int), expected: 789}, {name: "val to pointer", from: 999, to: new(*int), expected: ptr(999)}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { convert.To(tc.from, tc.to) // 获取 to 指针指向的实际值 actual := reflect.ValueOf(tc.to).Elem().Interface() if !reflect.DeepEqual(actual, tc.expected) { t.Errorf("[%s] Failed: from(%v) expected(%v) but got(%v)", tc.name, tc.from, tc.expected, actual) } }) } } // 5. 复杂映射与去摩擦 Key 匹配测试 func TestComplexFrictionlessMapping(t *testing.T) { // 场景:Map 键名非常混乱,Struct 嵌套,目标存在旧数据 type Sub struct { Age int } type User struct { UserID int UserName string SubInfo Sub } from := map[string]any{ "user_id": 1001, // 下划线 "USER-NAME": "Andy", // 中划线+大写 "subinfo": map[string]any{ // 嵌套+全小写 "age": "18", // 类型不一致 (string -> int) }, } var to User to.UserID = 999 // 预设旧数据,验证是否被正确覆盖 convert.To(from, &to) if to.UserID != 1001 { t.Errorf("UserID match failed: %d", to.UserID) } if to.UserName != "Andy" { t.Errorf("UserName match failed: %s", to.UserName) } if to.SubInfo.Age != 18 { t.Errorf("SubInfo.Age match failed: %d", to.SubInfo.Age) } } // 6. 函数转换测试 (Func to Func) func TestFuncConversion(t *testing.T) { // 源函数:接收 int, string,返回 int, string f1 := func(a int, b string) (int, string) { return a + 1, b + "!" } // 目标函数:意图是接收 string, any,返回 string, any var f2 func(string, any) (string, any) convert.To(f1, &f2) if f2 == nil { t.Fatal("Converted function is nil") } r1, r2 := f2("10", "hello") if r1 != "11" || r2 != "hello!" { t.Errorf("Func conversion failed: r1=%v, r2=%v", r1, r2) } } // 7. Parse 钩子测试 type HookStruct struct { Status int } func (h *HookStruct) ParseStatus(v any) int { s := reflect.ValueOf(v).String() if s == "active" { return 1 } return 0 } func TestParseHook(t *testing.T) { from := map[string]any{"status": "active"} var to HookStruct convert.To(from, &to) if to.Status != 1 { t.Errorf("Parse hook failed, got %d", to.Status) } } // 辅助函数 func ptr[T any](v T) *T { return &v } // --- 性能测试 --- func BenchmarkMatrixConvert(b *testing.B) { from := map[string]any{"id": "123", "name": "test"} type Target struct { ID int Name string } var to Target for i := 0; i < b.N; i++ { convert.To(from, &to) } }