322 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			322 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package reflect_test
 | |
| 
 | |
| import (
 | |
| 	"net/url"
 | |
| 	"reflect"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	rutil "go.unistack.org/micro/v4/util/reflect"
 | |
| )
 | |
| 
 | |
| 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) {
 | |
| 	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 TestStructFieldByPath(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 TestStructFieldByTag(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 TestStructFieldByName(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 TestURLMap(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)
 | |
| }
 |