chore: add more tests (#3324)

master
Kevin Wan 1 year ago committed by GitHub
parent d61a55f779
commit 6b4d0d89c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -176,7 +176,12 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
switch dereffedBaseKind { switch dereffedBaseKind {
case reflect.Struct: case reflect.Struct:
target := reflect.New(dereffedBaseType) target := reflect.New(dereffedBaseType)
if err := u.Unmarshal(ithValue.(map[string]any), target.Interface()); err != nil { val, ok := ithValue.(map[string]any)
if !ok {
return errTypeMismatch
}
if err := u.Unmarshal(val, target.Interface()); err != nil {
return err return err
} }

@ -557,6 +557,15 @@ func TestUnmarshalIntWithString(t *testing.T) {
var in inner var in inner
assert.Error(t, UnmarshalKey(m, &in)) assert.Error(t, UnmarshalKey(m, &in))
}) })
t.Run("invalid options", func(t *testing.T) {
type Value struct {
Name string `key:"name,options="`
}
var v Value
assert.Error(t, UnmarshalKey(emptyMap, &v))
})
} }
func TestUnmarshalBoolSliceRequired(t *testing.T) { func TestUnmarshalBoolSliceRequired(t *testing.T) {
@ -675,28 +684,54 @@ func TestUnmarshalFloatSliceWithDefault(t *testing.T) {
} }
func TestUnmarshalStringSliceWithDefault(t *testing.T) { func TestUnmarshalStringSliceWithDefault(t *testing.T) {
type inner struct { t.Run("slice with default", func(t *testing.T) {
Strs []string `key:"strs,default=[foo,bar,woo]"` type inner struct {
Strps []*string `key:"strs,default=[foo,bar,woo]"` Strs []string `key:"strs,default=[foo,bar,woo]"`
Strpps []**string `key:"strs,default=[foo,bar,woo]"` Strps []*string `key:"strs,default=[foo,bar,woo]"`
} Strpps []**string `key:"strs,default=[foo,bar,woo]"`
}
var in inner var in inner
if assert.NoError(t, UnmarshalKey(nil, &in)) { if assert.NoError(t, UnmarshalKey(nil, &in)) {
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, in.Strs) assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, in.Strs)
var ss []string
for _, s := range in.Strps {
ss = append(ss, *s)
}
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, ss)
var ss []string var sss []string
for _, s := range in.Strps { for _, s := range in.Strpps {
ss = append(ss, *s) sss = append(sss, **s)
}
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, sss)
} }
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, ss) })
var sss []string t.Run("slice with default on errors", func(t *testing.T) {
for _, s := range in.Strpps { type (
sss = append(sss, **s) holder struct {
Chan []chan int
}
inner struct {
Strs []holder `key:"strs,default=[foo,bar,woo]"`
}
)
var in inner
assert.Error(t, UnmarshalKey(nil, &in))
})
t.Run("slice with default on errors", func(t *testing.T) {
type inner struct {
Strs []complex64 `key:"strs,default=[foo,bar,woo]"`
} }
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, sss)
} var in inner
assert.Error(t, UnmarshalKey(nil, &in))
})
} }
func TestUnmarshalStringSliceWithDefaultHasSpaces(t *testing.T) { func TestUnmarshalStringSliceWithDefaultHasSpaces(t *testing.T) {
@ -1327,25 +1362,71 @@ func TestUnmarshalStructOptionalDependsNotErrorDetails(t *testing.T) {
} }
func TestUnmarshalStructOptionalDependsNotNested(t *testing.T) { func TestUnmarshalStructOptionalDependsNotNested(t *testing.T) {
type address struct { t.Run("mutal optionals", func(t *testing.T) {
Optional string `key:",optional"` type address struct {
OptionalDepends string `key:",optional=!Optional"` Optional string `key:",optional"`
} OptionalDepends string `key:",optional=!Optional"`
type combo struct { }
Name string `key:"name,optional"` type combo struct {
Address address `key:"address"` Name string `key:"name,optional"`
} Address address `key:"address"`
type inner struct { }
Name string `key:"name"` type inner struct {
Combo combo `key:"combo"` Name string `key:"name"`
} Combo combo `key:"combo"`
}
m := map[string]any{ m := map[string]any{
"name": "kevin", "name": "kevin",
} }
var in inner var in inner
assert.Error(t, UnmarshalKey(m, &in)) assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("bad format", func(t *testing.T) {
type address struct {
Optional string `key:",optional"`
OptionalDepends string `key:",optional=!Optional=abcd"`
}
type combo struct {
Name string `key:"name,optional"`
Address address `key:"address"`
}
type inner struct {
Name string `key:"name"`
Combo combo `key:"combo"`
}
m := map[string]any{
"name": "kevin",
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
t.Run("invalid option", func(t *testing.T) {
type address struct {
Optional string `key:",optional"`
OptionalDepends string `key:",opt=abcd"`
}
type combo struct {
Name string `key:"name,optional"`
Address address `key:"address"`
}
type inner struct {
Name string `key:"name"`
Combo combo `key:"combo"`
}
m := map[string]any{
"name": "kevin",
}
var in inner
assert.Error(t, UnmarshalKey(m, &in))
})
} }
func TestUnmarshalStructOptionalNestedDifferentKey(t *testing.T) { func TestUnmarshalStructOptionalNestedDifferentKey(t *testing.T) {
@ -3855,20 +3936,37 @@ func TestUnmarshalValuer(t *testing.T) {
} }
func TestUnmarshal_EnvString(t *testing.T) { func TestUnmarshal_EnvString(t *testing.T) {
type Value struct { t.Run("valid env", func(t *testing.T) {
Name string `key:"name,env=TEST_NAME_STRING"` type Value struct {
} Name string `key:"name,env=TEST_NAME_STRING"`
}
const ( const (
envName = "TEST_NAME_STRING" envName = "TEST_NAME_STRING"
envVal = "this is a name" envVal = "this is a name"
) )
t.Setenv(envName, envVal) t.Setenv(envName, envVal)
var v Value var v Value
if assert.NoError(t, UnmarshalKey(emptyMap, &v)) { if assert.NoError(t, UnmarshalKey(emptyMap, &v)) {
assert.Equal(t, envVal, v.Name) assert.Equal(t, envVal, v.Name)
} }
})
t.Run("invalid env", func(t *testing.T) {
type Value struct {
Name string `key:"name,env=TEST_NAME_STRING=invalid"`
}
const (
envName = "TEST_NAME_STRING"
envVal = "this is a name"
)
t.Setenv(envName, envVal)
var v Value
assert.Error(t, UnmarshalKey(emptyMap, &v))
})
} }
func TestUnmarshal_EnvStringOverwrite(t *testing.T) { func TestUnmarshal_EnvStringOverwrite(t *testing.T) {
@ -4044,20 +4142,22 @@ func TestUnmarshal_EnvDurationBadValue(t *testing.T) {
} }
func TestUnmarshal_EnvWithOptions(t *testing.T) { func TestUnmarshal_EnvWithOptions(t *testing.T) {
type Value struct { t.Run("valid options", func(t *testing.T) {
Name string `key:"name,env=TEST_NAME_ENV_OPTIONS_MATCH,options=[abc,123,xyz]"` type Value struct {
} Name string `key:"name,env=TEST_NAME_ENV_OPTIONS_MATCH,options=[abc,123,xyz]"`
}
const ( const (
envName = "TEST_NAME_ENV_OPTIONS_MATCH" envName = "TEST_NAME_ENV_OPTIONS_MATCH"
envVal = "123" envVal = "123"
) )
t.Setenv(envName, envVal) t.Setenv(envName, envVal)
var v Value var v Value
if assert.NoError(t, UnmarshalKey(emptyMap, &v)) { if assert.NoError(t, UnmarshalKey(emptyMap, &v)) {
assert.Equal(t, envVal, v.Name) assert.Equal(t, envVal, v.Name)
} }
})
} }
func TestUnmarshal_EnvWithOptionsWrongValueBool(t *testing.T) { func TestUnmarshal_EnvWithOptionsWrongValueBool(t *testing.T) {

@ -372,8 +372,6 @@ func parseOption(fieldOpts *fieldOptions, fieldName, option string) error {
default: default:
return fmt.Errorf("field %q has wrong optional", fieldName) return fmt.Errorf("field %q has wrong optional", fieldName)
} }
case option == optionalOption:
fieldOpts.Optional = true
case strings.HasPrefix(option, optionsOption): case strings.HasPrefix(option, optionsOption):
val, err := parseProperty(fieldName, optionsOption, option) val, err := parseProperty(fieldName, optionsOption, option)
if err != nil { if err != nil {

@ -241,7 +241,8 @@ func TestValidatePtrWithZeroValue(t *testing.T) {
func TestSetValueNotSettable(t *testing.T) { func TestSetValueNotSettable(t *testing.T) {
var i int var i int
assert.NotNil(t, setValueFromString(reflect.Int, reflect.ValueOf(i), "1")) 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) { func TestParseKeyAndOptionsErrors(t *testing.T) {
@ -300,3 +301,36 @@ func TestSetValueFormatErrors(t *testing.T) {
}) })
} }
} }
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"))
}

Loading…
Cancel
Save