package reflect_test import ( "net/url" "reflect" "testing" "time" rutil "go.unistack.org/micro/v3/util/reflect" ) func TestStructfields(t *testing.T) { type NestedConfig struct { Value string } type Config struct { Time time.Time Nested *NestedConfig Metadata map[string]int Broker string Addr []string Wait time.Duration Verbose bool } cfg := &Config{Nested: &NestedConfig{}} fields, err := rutil.StructFields(cfg) if err != nil { t.Fatal(err) } if len(fields) != 7 { for _, field := range fields { t.Logf("field %#+v\n", field) } t.Fatalf("invalid fields number: %d != %d", 7, len(fields)) } } func TestSetFieldByPath(t *testing.T) { type NestedStr struct { BBB string `json:"bbb"` CCC int `json:"ccc"` } type Str1 struct { Name []string `json:"name" codec:"flatten"` XXX string `json:"xxx"` Nested NestedStr `json:"nested"` } type Str2 struct { XXX string `json:"xxx"` Nested *NestedStr `json:"nested"` Name []string `json:"name" codec:"flatten"` } 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) } } func TestZeroFieldByPath(t *testing.T) { type NestedStr struct { BBB string `json:"bbb"` CCC int `json:"ccc"` } type Str1 struct { Name []string `json:"name" codec:"flatten"` XXX string `json:"xxx"` Nested NestedStr `json:"nested"` } type Str2 struct { XXX string `json:"xxx"` Nested *NestedStr `json:"nested"` Name []string `json:"name" codec:"flatten"` } var err error val1 := &Str1{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}} err = rutil.ZeroFieldByPath(val1, "Nested.BBB") if err != nil { t.Fatal(err) } err = rutil.ZeroFieldByPath(val1, "Nested") 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}} err = rutil.ZeroFieldByPath(val2, "Nested") if err != nil { t.Fatal(err) } if val2.Nested != nil { t.Fatalf("zero field not works: %v", val2) } } 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}} fields, err := rutil.StructFieldsMap(val) if err != nil { t.Fatal(err) } if v, ok := fields["Nested.BBB"]; !ok || v != "ddd" { t.Fatalf("invalid field from %v", fields) } } 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 TestStructByPath(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}} field, err := rutil.StructFieldByPath(val, "Nested.CCC") if err != nil { t.Fatal(err) } if reflect.Indirect(reflect.ValueOf(field)).Int() != 9 { t.Fatalf("invalid elem returned: %v", field) } } func TestStructByTag(t *testing.T) { type Str struct { Name []string `json:"name" codec:"flatten"` } val := &Str{Name: []string{"first", "second"}} iface, err := rutil.StructFieldByTag(val, "codec", "flatten") if err != nil { t.Fatal(err) } if v, ok := iface.(*[]string); !ok { t.Fatalf("not *[]string %v", iface) } else if len(*v) != 2 { t.Fatalf("invalid number %v", iface) } } func TestStructByName(t *testing.T) { type Str struct { Name []string `json:"name" codec:"flatten"` } val := &Str{Name: []string{"first", "second"}} iface, err := rutil.StructFieldByName(val, "Name") if err != nil { t.Fatal(err) } if v, ok := iface.([]string); !ok { t.Fatalf("not []string %v", iface) } else if len(v) != 2 { t.Fatalf("invalid number %v", iface) } } func TestStructURLValues(t *testing.T) { type Str struct { Str *Str `json:"str"` Name string `json:"name"` Args []int `json:"args"` } val := &Str{Name: "test_name", Args: []int{1, 2, 3}, Str: &Str{Name: "nested_name"}} data, err := rutil.StructURLValues(val, "", []string{"json"}) if err != nil { t.Fatal(err) } if data.Get("name") != "test_name" { t.Fatalf("invalid data: %v", data) } } 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) } mp, err := rutil.URLMap(u.RawQuery) 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) } } func TestURLVars(t *testing.T) { 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) } mp, err := rutil.URLMap(u.RawQuery) if err != nil { t.Fatal(err) } _ = mp } 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" if ok := rutil.IsZero(testStr1); ok { t.Fatalf("zero ret on non zero struct: %#+v", testStr1) } testStr1.Name = "" testStr1.Value = "" testStr1.Nested.NestedName = "" if ok := rutil.IsZero(testStr1); !ok { t.Fatalf("non zero ret on zero struct: %#+v", testStr1) } type testStr3 struct { Nested string } type testStr2 struct { Nested *testStr3 Name string } vtest := &testStr2{ Name: "test_name", Nested: &testStr3{Nested: "nested_name"}, } if ok := rutil.IsZero(vtest); ok { t.Fatalf("zero ret on non zero struct: %#+v", vtest) } vtest.Nested = nil vtest.Name = "" if ok := rutil.IsZero(vtest); !ok { t.Fatalf("non zero ret on zero struct: %#+v", vtest) } // t.Logf("XX %#+v\n", ok) }