feat: validate value in options for mapping (#2616)
This commit is contained in:
@@ -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 BenchmarkUnmarshalStruct(b *testing.B) {
|
func TestUnmarshal_EnvWithOptionsWrongValueBool(t *testing.T) {
|
||||||
b.ReportAllocs()
|
type Value struct {
|
||||||
|
Enable bool `key:"enable,env=TEST_NAME_ENV_OPTIONS_BOOL,options=[true]"`
|
||||||
m := map[string]interface{}{
|
|
||||||
"Ids": []map[string]interface{}{
|
|
||||||
{
|
|
||||||
"First": 1,
|
|
||||||
"Second": 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
const (
|
||||||
var v struct {
|
envName = "TEST_NAME_ENV_OPTIONS_BOOL"
|
||||||
Ids []struct {
|
envVal = "false"
|
||||||
First int
|
)
|
||||||
Second int
|
os.Setenv(envName, envVal)
|
||||||
}
|
defer os.Unsetenv(envName)
|
||||||
}
|
|
||||||
if err := UnmarshalKey(m, &v); err != nil {
|
var v Value
|
||||||
b.Fatal(err)
|
assert.Error(t, UnmarshalKey(emptyMap, &v))
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMapToStruct(b *testing.B) {
|
func TestUnmarshal_EnvWithOptionsWrongValueDuration(t *testing.T) {
|
||||||
data := map[string]interface{}{
|
type Value struct {
|
||||||
"valid": "1",
|
Duration time.Duration `key:"duration,env=TEST_NAME_ENV_OPTIONS_DURATION,options=[1s,2s,3s]"`
|
||||||
"age": "5",
|
|
||||||
"name": "liao",
|
|
||||||
}
|
|
||||||
type anonymous struct {
|
|
||||||
Valid bool
|
|
||||||
Age int
|
|
||||||
Name string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
const (
|
||||||
var an anonymous
|
envName = "TEST_NAME_ENV_OPTIONS_DURATION"
|
||||||
if valid, ok := data["valid"]; ok {
|
envVal = "4s"
|
||||||
an.Valid = valid == "1"
|
)
|
||||||
}
|
os.Setenv(envName, envVal)
|
||||||
if age, ok := data["age"]; ok {
|
defer os.Unsetenv(envName)
|
||||||
ages, _ := age.(string)
|
|
||||||
an.Age, _ = strconv.Atoi(ages)
|
var v Value
|
||||||
}
|
assert.Error(t, UnmarshalKey(emptyMap, &v))
|
||||||
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"`
|
|
||||||
Age int `key:"age,string"`
|
|
||||||
Name string `key:"name"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
const (
|
||||||
var an anonymous
|
envName = "TEST_NAME_ENV_OPTIONS_AGE"
|
||||||
UnmarshalKey(data, &an)
|
envVal = "30"
|
||||||
|
)
|
||||||
|
os.Setenv(envName, envVal)
|
||||||
|
defer os.Unsetenv(envName)
|
||||||
|
|
||||||
|
var v Value
|
||||||
|
assert.Error(t, UnmarshalKey(emptyMap, &v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshal_EnvWithOptionsWrongValueString(t *testing.T) {
|
||||||
|
type Value struct {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user