You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-zero/core/mapping/utils_test.go

337 lines
7.0 KiB
Go

package mapping
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
const testTagName = "key"
type Foo struct {
Str string
StrWithTag string `key:"stringwithtag"`
StrWithTagAndOption string `key:"stringwithtag,string"`
}
func TestDerefInt(t *testing.T) {
i := 1
s := "hello"
number := struct {
f float64
}{
f: 6.4,
}
cases := []struct {
t reflect.Type
expect reflect.Kind
}{
{
t: reflect.TypeOf(i),
expect: reflect.Int,
},
{
t: reflect.TypeOf(&i),
expect: reflect.Int,
},
{
t: reflect.TypeOf(s),
expect: reflect.String,
},
{
t: reflect.TypeOf(&s),
expect: reflect.String,
},
{
t: reflect.TypeOf(number.f),
expect: reflect.Float64,
},
{
t: reflect.TypeOf(&number.f),
expect: reflect.Float64,
},
}
for _, each := range cases {
t.Run(each.t.String(), func(t *testing.T) {
assert.Equal(t, each.expect, Deref(each.t).Kind())
})
}
}
func TestDerefValInt(t *testing.T) {
i := 1
s := "hello"
number := struct {
f float64
}{
f: 6.4,
}
cases := []struct {
t reflect.Value
expect reflect.Kind
}{
{
t: reflect.ValueOf(i),
expect: reflect.Int,
},
{
t: reflect.ValueOf(&i),
expect: reflect.Int,
},
{
t: reflect.ValueOf(s),
expect: reflect.String,
},
{
t: reflect.ValueOf(&s),
expect: reflect.String,
},
{
t: reflect.ValueOf(number.f),
expect: reflect.Float64,
},
{
t: reflect.ValueOf(&number.f),
expect: reflect.Float64,
},
}
for _, each := range cases {
t.Run(each.t.String(), func(t *testing.T) {
assert.Equal(t, each.expect, ensureValue(each.t).Kind())
})
}
}
func TestParseKeyAndOptionWithoutTag(t *testing.T) {
var foo Foo
rte := reflect.TypeOf(&foo).Elem()
field, _ := rte.FieldByName("Str")
key, options, err := parseKeyAndOptions(testTagName, field)
assert.Nil(t, err)
assert.Equal(t, "Str", key)
assert.Nil(t, options)
}
func TestParseKeyAndOptionWithTagWithoutOption(t *testing.T) {
var foo Foo
rte := reflect.TypeOf(&foo).Elem()
field, _ := rte.FieldByName("StrWithTag")
key, options, err := parseKeyAndOptions(testTagName, field)
assert.Nil(t, err)
assert.Equal(t, "stringwithtag", key)
assert.Nil(t, options)
}
func TestParseKeyAndOptionWithTagAndOption(t *testing.T) {
var foo Foo
rte := reflect.TypeOf(&foo).Elem()
field, _ := rte.FieldByName("StrWithTagAndOption")
key, options, err := parseKeyAndOptions(testTagName, field)
assert.Nil(t, err)
assert.Equal(t, "stringwithtag", key)
assert.True(t, options.FromString)
}
func TestParseSegments(t *testing.T) {
tests := []struct {
input string
expect []string
}{
{
input: "",
expect: []string{},
},
{
input: " ",
expect: []string{},
},
{
input: ",",
expect: []string{""},
},
{
input: "foo,",
expect: []string{"foo"},
},
{
input: ",foo",
// the first empty string cannot be ignored, it's the key.
expect: []string{"", "foo"},
},
{
input: "foo",
expect: []string{"foo"},
},
{
input: "foo,bar",
expect: []string{"foo", "bar"},
},
{
input: "foo,bar,baz",
expect: []string{"foo", "bar", "baz"},
},
{
input: "foo,options=a|b",
expect: []string{"foo", "options=a|b"},
},
{
input: "foo,bar,default=[baz,qux]",
expect: []string{"foo", "bar", "default=[baz,qux]"},
},
{
input: "foo,bar,options=[baz,qux]",
expect: []string{"foo", "bar", "options=[baz,qux]"},
},
{
input: `foo\,bar,options=[baz,qux]`,
expect: []string{`foo,bar`, "options=[baz,qux]"},
},
{
input: `foo,bar,options=\[baz,qux]`,
expect: []string{"foo", "bar", "options=[baz", "qux]"},
},
{
input: `foo,bar,options=[baz\,qux]`,
expect: []string{"foo", "bar", `options=[baz\,qux]`},
},
{
input: `foo\,bar,options=[baz,qux],default=baz`,
expect: []string{`foo,bar`, "options=[baz,qux]", "default=baz"},
},
{
input: `foo\,bar,options=[baz,qux, quux],default=[qux, baz]`,
expect: []string{`foo,bar`, "options=[baz,qux, quux]", "default=[qux, baz]"},
},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
assert.ElementsMatch(t, test.expect, parseSegments(test.input))
})
}
}
func TestValidatePtrWithNonPtr(t *testing.T) {
var foo string
rve := reflect.ValueOf(foo)
assert.NotNil(t, ValidatePtr(&rve))
}
func TestValidatePtrWithPtr(t *testing.T) {
var foo string
rve := reflect.ValueOf(&foo)
assert.Nil(t, ValidatePtr(&rve))
}
func TestValidatePtrWithNilPtr(t *testing.T) {
var foo *string
rve := reflect.ValueOf(foo)
assert.NotNil(t, ValidatePtr(&rve))
}
func TestValidatePtrWithZeroValue(t *testing.T) {
var s string
e := reflect.Zero(reflect.TypeOf(s))
assert.NotNil(t, ValidatePtr(&e))
}
func TestSetValueNotSettable(t *testing.T) {
var i int
assert.Error(t, setValueFromString(reflect.Int, reflect.ValueOf(i), "1"))
assert.Error(t, validateAndSetValue(reflect.Int, reflect.ValueOf(i), "1", nil))
}
func TestParseKeyAndOptionsErrors(t *testing.T) {
type Bar struct {
OptionsValue string `key:",options=a=b"`
DefaultValue string `key:",default=a=b"`
}
var bar Bar
_, _, err := parseKeyAndOptions("key", reflect.TypeOf(&bar).Elem().Field(0))
assert.NotNil(t, err)
_, _, err = parseKeyAndOptions("key", reflect.TypeOf(&bar).Elem().Field(1))
assert.NotNil(t, err)
}
func TestSetValueFormatErrors(t *testing.T) {
type Bar struct {
IntValue int
UintValue uint
FloatValue float32
MapValue map[string]any
}
var bar Bar
tests := []struct {
kind reflect.Kind
target reflect.Value
value string
}{
{
kind: reflect.Int,
target: reflect.ValueOf(&bar.IntValue).Elem(),
value: "a",
},
{
kind: reflect.Uint,
target: reflect.ValueOf(&bar.UintValue).Elem(),
value: "a",
},
{
kind: reflect.Float32,
target: reflect.ValueOf(&bar.FloatValue).Elem(),
value: "a",
},
{
kind: reflect.Map,
target: reflect.ValueOf(&bar.MapValue).Elem(),
},
}
for _, test := range tests {
t.Run(test.kind.String(), func(t *testing.T) {
err := setValueFromString(test.kind, test.target, test.value)
assert.NotEqual(t, errValueNotSettable, err)
assert.NotNil(t, err)
})
}
}
func TestValidateValueRange(t *testing.T) {
t.Run("float", func(t *testing.T) {
assert.NoError(t, validateValueRange(1.2, nil))
})
t.Run("float number range", func(t *testing.T) {
assert.NoError(t, validateNumberRange(1.2, nil))
})
t.Run("bad float", func(t *testing.T) {
assert.Error(t, validateValueRange("a", &fieldOptionsWithContext{
Range: &numberRange{},
}))
})
t.Run("bad float validate", func(t *testing.T) {
var v struct {
Foo float32
}
assert.Error(t, validateAndSetValue(reflect.Int, reflect.ValueOf(&v).Elem().Field(0),
"1", &fieldOptionsWithContext{
Range: &numberRange{
left: 2,
right: 3,
},
}))
})
}
func TestSetMatchedPrimitiveValue(t *testing.T) {
assert.Error(t, setMatchedPrimitiveValue(reflect.Func, reflect.ValueOf(2), "1"))
}