2021-09-29 13:09:48 +03:00
|
|
|
package reflect_test
|
2021-02-06 18:13:43 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"net/url"
|
2021-09-29 13:09:48 +03:00
|
|
|
"reflect"
|
2021-02-06 18:13:43 +03:00
|
|
|
"testing"
|
2021-10-27 22:51:35 +03:00
|
|
|
"time"
|
2021-09-29 13:09:48 +03:00
|
|
|
|
2023-04-11 22:20:37 +03:00
|
|
|
rutil "go.unistack.org/micro/v4/util/reflect"
|
2021-02-06 18:13:43 +03:00
|
|
|
)
|
|
|
|
|
2022-04-22 09:24:34 +03:00
|
|
|
func TestStructFields(t *testing.T) {
|
|
|
|
type NestedStr struct {
|
|
|
|
BBB string
|
|
|
|
CCC int
|
|
|
|
}
|
|
|
|
type Str struct {
|
|
|
|
Name []string `json:"name" codec:"flatten"`
|
|
|
|
XXX string `json:"xxx"`
|
|
|
|
Nested NestedStr
|
|
|
|
}
|
|
|
|
|
|
|
|
val := &Str{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
|
|
|
|
fields, err := rutil.StructFields(val)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
var ok bool
|
|
|
|
for _, field := range fields {
|
|
|
|
if field.Path == "Nested.CCC" {
|
|
|
|
ok = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !ok {
|
|
|
|
t.Fatalf("struct fields returns invalid path: %v", fields)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestStructFieldsNested(t *testing.T) {
|
2022-03-25 14:24:20 +03:00
|
|
|
type NestedConfig struct {
|
|
|
|
Value string
|
|
|
|
}
|
2021-10-27 22:51:35 +03:00
|
|
|
type Config struct {
|
|
|
|
Time time.Time
|
2022-03-25 14:24:20 +03:00
|
|
|
Nested *NestedConfig
|
2021-10-27 22:51:35 +03:00
|
|
|
Metadata map[string]int
|
|
|
|
Broker string
|
|
|
|
Addr []string
|
2022-03-22 14:54:43 +03:00
|
|
|
Wait time.Duration
|
2021-10-27 22:51:35 +03:00
|
|
|
Verbose bool
|
|
|
|
}
|
2022-03-25 14:24:20 +03:00
|
|
|
cfg := &Config{Nested: &NestedConfig{}}
|
2021-10-27 22:51:35 +03:00
|
|
|
fields, err := rutil.StructFields(cfg)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2022-03-25 14:24:20 +03:00
|
|
|
if len(fields) != 7 {
|
|
|
|
for _, field := range fields {
|
|
|
|
t.Logf("field %#+v\n", field)
|
|
|
|
}
|
|
|
|
t.Fatalf("invalid fields number: %d != %d", 7, len(fields))
|
2021-10-27 22:51:35 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-29 00:40:58 +03:00
|
|
|
func TestSetFieldByPathMultiple(t *testing.T) {
|
|
|
|
var err error
|
|
|
|
tv := "test_val"
|
|
|
|
type Str1 struct {
|
|
|
|
Name []string `json:"name"`
|
|
|
|
}
|
|
|
|
val1 := &Str1{}
|
|
|
|
|
|
|
|
err = rutil.SetFieldByPath(val1, tv, ".Name")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(val1.Name) != 1 {
|
|
|
|
t.Fatal("assign error")
|
|
|
|
} else if val1.Name[0] != tv {
|
|
|
|
t.Fatal("assign error")
|
|
|
|
}
|
|
|
|
|
|
|
|
type Str2 struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
}
|
|
|
|
val2 := &Str2{}
|
|
|
|
|
|
|
|
err = rutil.SetFieldByPath(val2, []string{tv}, ".Name")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(val1.Name) != 1 {
|
|
|
|
t.Fatal("assign error")
|
|
|
|
} else if val1.Name[0] != tv {
|
|
|
|
t.Fatal("assign error")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-26 14:12:37 +03:00
|
|
|
func TestSetFieldByPath(t *testing.T) {
|
|
|
|
type NestedStr struct {
|
2021-10-27 12:55:48 +03:00
|
|
|
BBB string `json:"bbb"`
|
2021-10-27 22:51:35 +03:00
|
|
|
CCC int `json:"ccc"`
|
2021-10-26 14:12:37 +03:00
|
|
|
}
|
|
|
|
type Str1 struct {
|
2021-10-27 22:51:35 +03:00
|
|
|
Name []string `json:"name" codec:"flatten"`
|
|
|
|
XXX string `json:"xxx"`
|
2021-10-27 12:55:48 +03:00
|
|
|
Nested NestedStr `json:"nested"`
|
2021-10-26 14:12:37 +03:00
|
|
|
}
|
|
|
|
type Str2 struct {
|
2021-10-27 22:51:35 +03:00
|
|
|
XXX string `json:"xxx"`
|
2021-10-27 12:55:48 +03:00
|
|
|
Nested *NestedStr `json:"nested"`
|
2021-10-27 22:51:35 +03:00
|
|
|
Name []string `json:"name" codec:"flatten"`
|
2021-10-26 14:12:37 +03:00
|
|
|
}
|
|
|
|
var err error
|
|
|
|
val1 := &Str1{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
|
|
|
|
val2 := &Str2{Name: []string{"first", "second"}, XXX: "ttt", Nested: &NestedStr{BBB: "ddd", CCC: 9}}
|
|
|
|
err = rutil.SetFieldByPath(val1, "xxx", "Nested.BBB")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if val1.Nested.BBB != "xxx" {
|
|
|
|
t.Fatalf("SetFieldByPath not works: %#+v", val1)
|
|
|
|
}
|
|
|
|
err = rutil.SetFieldByPath(val2, "xxx", "Nested.BBB")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if val2.Nested.BBB != "xxx" {
|
|
|
|
t.Fatalf("SetFieldByPath not works: %#+v", val1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-25 14:41:19 +03:00
|
|
|
func TestZeroFieldByPath(t *testing.T) {
|
|
|
|
type NestedStr struct {
|
2021-10-27 12:55:48 +03:00
|
|
|
BBB string `json:"bbb"`
|
2021-10-27 22:51:35 +03:00
|
|
|
CCC int `json:"ccc"`
|
2021-10-25 14:41:19 +03:00
|
|
|
}
|
|
|
|
type Str1 struct {
|
2021-10-27 22:51:35 +03:00
|
|
|
Name []string `json:"name" codec:"flatten"`
|
|
|
|
XXX string `json:"xxx"`
|
2021-10-27 12:55:48 +03:00
|
|
|
Nested NestedStr `json:"nested"`
|
2021-10-25 14:41:19 +03:00
|
|
|
}
|
|
|
|
type Str2 struct {
|
2021-10-27 22:51:35 +03:00
|
|
|
XXX string `json:"xxx"`
|
2021-10-27 12:55:48 +03:00
|
|
|
Nested *NestedStr `json:"nested"`
|
2021-10-27 22:51:35 +03:00
|
|
|
Name []string `json:"name" codec:"flatten"`
|
2021-10-25 14:41:19 +03:00
|
|
|
}
|
|
|
|
var err error
|
|
|
|
val1 := &Str1{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
|
|
|
|
|
2021-10-27 12:55:48 +03:00
|
|
|
err = rutil.ZeroFieldByPath(val1, "Nested.BBB")
|
2021-10-25 14:41:19 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2021-10-27 12:55:48 +03:00
|
|
|
err = rutil.ZeroFieldByPath(val1, "Nested")
|
2021-10-25 14:41:19 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if val1.Nested.BBB == "ddd" {
|
|
|
|
t.Fatalf("zero field not works: %v", val1)
|
|
|
|
}
|
|
|
|
|
|
|
|
val2 := &Str2{Name: []string{"first", "second"}, XXX: "ttt", Nested: &NestedStr{BBB: "ddd", CCC: 9}}
|
2021-10-27 12:55:48 +03:00
|
|
|
err = rutil.ZeroFieldByPath(val2, "Nested")
|
2021-10-25 14:41:19 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if val2.Nested != nil {
|
|
|
|
t.Fatalf("zero field not works: %v", val2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 15:45:31 +03:00
|
|
|
func TestStructFieldsMap(t *testing.T) {
|
|
|
|
type NestedStr struct {
|
|
|
|
BBB string
|
|
|
|
CCC int
|
|
|
|
}
|
|
|
|
type Str struct {
|
|
|
|
Name []string `json:"name" codec:"flatten"`
|
|
|
|
XXX string `json:"xxx"`
|
|
|
|
Nested NestedStr
|
|
|
|
}
|
|
|
|
|
|
|
|
val := &Str{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
|
2021-09-29 13:09:48 +03:00
|
|
|
fields, err := rutil.StructFieldsMap(val)
|
2021-07-22 15:45:31 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if v, ok := fields["Nested.BBB"]; !ok || v != "ddd" {
|
|
|
|
t.Fatalf("invalid field from %v", fields)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-22 09:24:34 +03:00
|
|
|
func TestStructFieldByPath(t *testing.T) {
|
2021-07-22 15:45:31 +03:00
|
|
|
type NestedStr struct {
|
|
|
|
BBB string
|
|
|
|
CCC int
|
|
|
|
}
|
|
|
|
type Str struct {
|
|
|
|
Name []string `json:"name" codec:"flatten"`
|
|
|
|
XXX string `json:"xxx"`
|
|
|
|
Nested NestedStr
|
|
|
|
}
|
|
|
|
|
|
|
|
val := &Str{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
|
2021-09-29 13:09:48 +03:00
|
|
|
field, err := rutil.StructFieldByPath(val, "Nested.CCC")
|
2021-07-22 15:45:31 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2021-09-29 13:09:48 +03:00
|
|
|
if reflect.Indirect(reflect.ValueOf(field)).Int() != 9 {
|
2021-07-22 15:45:31 +03:00
|
|
|
t.Fatalf("invalid elem returned: %v", field)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-22 09:24:34 +03:00
|
|
|
func TestStructFieldByTag(t *testing.T) {
|
2021-05-25 22:20:39 +03:00
|
|
|
type Str struct {
|
|
|
|
Name []string `json:"name" codec:"flatten"`
|
|
|
|
}
|
|
|
|
|
|
|
|
val := &Str{Name: []string{"first", "second"}}
|
|
|
|
|
2021-09-29 13:09:48 +03:00
|
|
|
iface, err := rutil.StructFieldByTag(val, "codec", "flatten")
|
2021-05-25 22:20:39 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2021-05-25 22:44:22 +03:00
|
|
|
if v, ok := iface.(*[]string); !ok {
|
|
|
|
t.Fatalf("not *[]string %v", iface)
|
|
|
|
} else if len(*v) != 2 {
|
2021-05-25 22:20:39 +03:00
|
|
|
t.Fatalf("invalid number %v", iface)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-22 09:24:34 +03:00
|
|
|
func TestStructFieldByName(t *testing.T) {
|
2021-05-25 22:20:39 +03:00
|
|
|
type Str struct {
|
|
|
|
Name []string `json:"name" codec:"flatten"`
|
|
|
|
}
|
|
|
|
|
|
|
|
val := &Str{Name: []string{"first", "second"}}
|
|
|
|
|
2021-09-29 13:09:48 +03:00
|
|
|
iface, err := rutil.StructFieldByName(val, "Name")
|
2021-05-25 22:20:39 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2021-10-27 12:55:48 +03:00
|
|
|
if v, ok := iface.([]string); !ok {
|
|
|
|
t.Fatalf("not []string %v", iface)
|
|
|
|
} else if len(v) != 2 {
|
2021-05-25 22:20:39 +03:00
|
|
|
t.Fatalf("invalid number %v", iface)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-01 00:30:15 +03:00
|
|
|
func TestStructURLValues(t *testing.T) {
|
|
|
|
type Str struct {
|
2021-04-27 08:32:47 +03:00
|
|
|
Str *Str `json:"str"`
|
2021-04-01 00:30:15 +03:00
|
|
|
Name string `json:"name"`
|
|
|
|
Args []int `json:"args"`
|
|
|
|
}
|
|
|
|
|
|
|
|
val := &Str{Name: "test_name", Args: []int{1, 2, 3}, Str: &Str{Name: "nested_name"}}
|
2021-09-29 13:09:48 +03:00
|
|
|
data, err := rutil.StructURLValues(val, "", []string{"json"})
|
2021-04-01 00:30:15 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if data.Get("name") != "test_name" {
|
|
|
|
t.Fatalf("invalid data: %v", data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-06 18:13:43 +03:00
|
|
|
func TestURLSliceVars(t *testing.T) {
|
|
|
|
u, err := url.Parse("http://localhost/v1/test/call/my_name?key=arg1&key=arg2&key=arg3")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2021-09-29 13:09:48 +03:00
|
|
|
mp, err := rutil.URLMap(u.RawQuery)
|
2021-02-06 18:13:43 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
v, ok := mp["key"]
|
|
|
|
if !ok {
|
|
|
|
t.Fatalf("key not exists: %#+v", mp)
|
|
|
|
}
|
|
|
|
|
|
|
|
vm, ok := v.([]interface{})
|
|
|
|
if !ok {
|
|
|
|
t.Fatalf("invalid key value")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(vm) != 3 {
|
|
|
|
t.Fatalf("missing key value: %#+v", mp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-22 09:24:34 +03:00
|
|
|
func TestURLMap(t *testing.T) {
|
2021-02-06 18:13:43 +03:00
|
|
|
u, err := url.Parse("http://localhost/v1/test/call/my_name?req=key&arg1=arg1&arg2=12345&nested.string_args=str1&nested.string_args=str2&arg2=54321")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2021-09-29 13:09:48 +03:00
|
|
|
mp, err := rutil.URLMap(u.RawQuery)
|
2021-02-06 18:13:43 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
_ = mp
|
|
|
|
}
|
2021-03-21 16:17:50 +03:00
|
|
|
|
|
|
|
func TestIsZero(t *testing.T) {
|
|
|
|
testStr1 := struct {
|
|
|
|
Name string
|
|
|
|
Value string
|
|
|
|
Nested struct {
|
|
|
|
NestedName string
|
|
|
|
}
|
|
|
|
}{
|
|
|
|
Name: "test_name",
|
|
|
|
Value: "test_value",
|
|
|
|
}
|
|
|
|
testStr1.Nested.NestedName = "nested_name"
|
|
|
|
|
2021-09-29 13:09:48 +03:00
|
|
|
if ok := rutil.IsZero(testStr1); ok {
|
2021-03-21 16:17:50 +03:00
|
|
|
t.Fatalf("zero ret on non zero struct: %#+v", testStr1)
|
|
|
|
}
|
|
|
|
|
|
|
|
testStr1.Name = ""
|
|
|
|
testStr1.Value = ""
|
|
|
|
testStr1.Nested.NestedName = ""
|
2021-09-29 13:09:48 +03:00
|
|
|
if ok := rutil.IsZero(testStr1); !ok {
|
2021-03-21 16:17:50 +03:00
|
|
|
t.Fatalf("non zero ret on zero struct: %#+v", testStr1)
|
|
|
|
}
|
|
|
|
|
|
|
|
type testStr3 struct {
|
|
|
|
Nested string
|
|
|
|
}
|
|
|
|
type testStr2 struct {
|
|
|
|
Nested *testStr3
|
2021-04-27 08:32:47 +03:00
|
|
|
Name string
|
2021-03-21 16:17:50 +03:00
|
|
|
}
|
|
|
|
vtest := &testStr2{
|
|
|
|
Name: "test_name",
|
|
|
|
Nested: &testStr3{Nested: "nested_name"},
|
|
|
|
}
|
2021-09-29 13:09:48 +03:00
|
|
|
if ok := rutil.IsZero(vtest); ok {
|
2021-03-21 16:17:50 +03:00
|
|
|
t.Fatalf("zero ret on non zero struct: %#+v", vtest)
|
|
|
|
}
|
|
|
|
vtest.Nested = nil
|
|
|
|
vtest.Name = ""
|
2021-09-29 13:09:48 +03:00
|
|
|
if ok := rutil.IsZero(vtest); !ok {
|
2021-03-21 16:17:50 +03:00
|
|
|
t.Fatalf("non zero ret on zero struct: %#+v", vtest)
|
|
|
|
}
|
|
|
|
|
2021-04-27 08:32:47 +03:00
|
|
|
// t.Logf("XX %#+v\n", ok)
|
2021-03-21 16:17:50 +03:00
|
|
|
}
|