feat: validate value in options for mapping (#2616)

master
Kevin Wan 2 years ago committed by GitHub
parent 79de932646
commit 06fafd2153
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -341,6 +341,10 @@ func (u *Unmarshaler) processFieldTextUnmarshaler(field reflect.StructField, val
func (u *Unmarshaler) processFieldWithEnvValue(field reflect.StructField, value reflect.Value, func (u *Unmarshaler) processFieldWithEnvValue(field reflect.StructField, value reflect.Value,
envVal string, opts *fieldOptionsWithContext, fullName string) error { envVal string, opts *fieldOptionsWithContext, fullName string) error {
if err := validateValueInOptions(envVal, opts.options()); err != nil {
return err
}
fieldKind := field.Type.Kind() fieldKind := field.Type.Kind()
switch fieldKind { switch fieldKind {
case reflect.Bool: case reflect.Bool:

@ -3254,91 +3254,85 @@ func TestUnmarshal_EnvDurationBadValue(t *testing.T) {
assert.NotNil(t, UnmarshalKey(emptyMap, &v)) assert.NotNil(t, UnmarshalKey(emptyMap, &v))
} }
func BenchmarkUnmarshalString(b *testing.B) { func TestUnmarshal_EnvWithOptions(t *testing.T) {
type inner struct { type Value struct {
Value string `key:"value"` Name string `key:"name,env=TEST_NAME_ENV_OPTIONS_MATCH,options=[abc,123,xyz]"`
}
m := map[string]interface{}{
"value": "first",
} }
for i := 0; i < b.N; i++ { const (
var in inner envName = "TEST_NAME_ENV_OPTIONS_MATCH"
if err := UnmarshalKey(m, &in); err != nil { envVal = "123"
b.Fatal(err) )
} os.Setenv(envName, envVal)
defer os.Unsetenv(envName)
var v Value
assert.NoError(t, UnmarshalKey(emptyMap, &v))
assert.Equal(t, envVal, v.Name)
} }
func TestUnmarshal_EnvWithOptionsWrongValueBool(t *testing.T) {
type Value struct {
Enable bool `key:"enable,env=TEST_NAME_ENV_OPTIONS_BOOL,options=[true]"`
} }
func BenchmarkUnmarshalStruct(b *testing.B) { const (
b.ReportAllocs() envName = "TEST_NAME_ENV_OPTIONS_BOOL"
envVal = "false"
)
os.Setenv(envName, envVal)
defer os.Unsetenv(envName)
m := map[string]interface{}{ var v Value
"Ids": []map[string]interface{}{ assert.Error(t, UnmarshalKey(emptyMap, &v))
{
"First": 1,
"Second": 2,
},
},
} }
for i := 0; i < b.N; i++ { func TestUnmarshal_EnvWithOptionsWrongValueDuration(t *testing.T) {
var v struct { type Value struct {
Ids []struct { Duration time.Duration `key:"duration,env=TEST_NAME_ENV_OPTIONS_DURATION,options=[1s,2s,3s]"`
First int
Second int
}
}
if err := UnmarshalKey(m, &v); err != nil {
b.Fatal(err)
}
}
} }
func BenchmarkMapToStruct(b *testing.B) { const (
data := map[string]interface{}{ envName = "TEST_NAME_ENV_OPTIONS_DURATION"
"valid": "1", envVal = "4s"
"age": "5", )
"name": "liao", os.Setenv(envName, envVal)
} defer os.Unsetenv(envName)
type anonymous struct {
Valid bool
Age int
Name string
}
for i := 0; i < b.N; i++ { var v Value
var an anonymous assert.Error(t, UnmarshalKey(emptyMap, &v))
if valid, ok := data["valid"]; ok {
an.Valid = valid == "1"
}
if age, ok := data["age"]; ok {
ages, _ := age.(string)
an.Age, _ = strconv.Atoi(ages)
}
if name, ok := data["name"]; ok {
names, _ := name.(string)
an.Name = names
}
}
} }
func BenchmarkUnmarshal(b *testing.B) { func TestUnmarshal_EnvWithOptionsWrongValueNumber(t *testing.T) {
data := map[string]interface{}{ type Value struct {
"valid": "1", Age int `key:"age,env=TEST_NAME_ENV_OPTIONS_AGE,options=[18,19,20]"`
"age": "5",
"name": "liao",
} }
type anonymous struct {
Valid bool `key:"valid,string"` const (
Age int `key:"age,string"` envName = "TEST_NAME_ENV_OPTIONS_AGE"
Name string `key:"name"` envVal = "30"
)
os.Setenv(envName, envVal)
defer os.Unsetenv(envName)
var v Value
assert.Error(t, UnmarshalKey(emptyMap, &v))
} }
for i := 0; i < b.N; i++ { func TestUnmarshal_EnvWithOptionsWrongValueString(t *testing.T) {
var an anonymous type Value struct {
UnmarshalKey(data, &an) Name string `key:"name,env=TEST_NAME_ENV_OPTIONS_STRING,options=[abc,123,xyz]"`
} }
const (
envName = "TEST_NAME_ENV_OPTIONS_STRING"
envVal = "this is a name"
)
os.Setenv(envName, envVal)
defer os.Unsetenv(envName)
var v Value
assert.Error(t, UnmarshalKey(emptyMap, &v))
} }
func TestUnmarshalJsonReaderMultiArray(t *testing.T) { func TestUnmarshalJsonReaderMultiArray(t *testing.T) {
@ -3581,3 +3575,90 @@ func BenchmarkDefaultValue(b *testing.B) {
} }
} }
} }
func BenchmarkUnmarshalString(b *testing.B) {
type inner struct {
Value string `key:"value"`
}
m := map[string]interface{}{
"value": "first",
}
for i := 0; i < b.N; i++ {
var in inner
if err := UnmarshalKey(m, &in); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkUnmarshalStruct(b *testing.B) {
b.ReportAllocs()
m := map[string]interface{}{
"Ids": []map[string]interface{}{
{
"First": 1,
"Second": 2,
},
},
}
for i := 0; i < b.N; i++ {
var v struct {
Ids []struct {
First int
Second int
}
}
if err := UnmarshalKey(m, &v); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkMapToStruct(b *testing.B) {
data := map[string]interface{}{
"valid": "1",
"age": "5",
"name": "liao",
}
type anonymous struct {
Valid bool
Age int
Name string
}
for i := 0; i < b.N; i++ {
var an anonymous
if valid, ok := data["valid"]; ok {
an.Valid = valid == "1"
}
if age, ok := data["age"]; ok {
ages, _ := age.(string)
an.Age, _ = strconv.Atoi(ages)
}
if name, ok := data["name"]; ok {
names, _ := name.(string)
an.Name = names
}
}
}
func BenchmarkUnmarshal(b *testing.B) {
data := map[string]interface{}{
"valid": "1",
"age": "5",
"name": "liao",
}
type anonymous struct {
Valid bool `key:"valid,string"`
Age int `key:"age,string"`
Name string `key:"name"`
}
for i := 0; i < b.N; i++ {
var an anonymous
UnmarshalKey(data, &an)
}
}

Loading…
Cancel
Save