fix: mapping optional dep not canonicaled (#2807)
This commit is contained in:
@@ -97,6 +97,30 @@ d = "abcd!@#$112"
|
|||||||
assert.Equal(t, "abcd!@#$112", val.D)
|
assert.Equal(t, "abcd!@#$112", val.D)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigOptional(t *testing.T) {
|
||||||
|
text := `a = "foo"
|
||||||
|
b = 1
|
||||||
|
c = "FOO"
|
||||||
|
d = "abcd"
|
||||||
|
`
|
||||||
|
tmpfile, err := createTempFile(".toml", text)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
defer os.Remove(tmpfile)
|
||||||
|
|
||||||
|
var val struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B int `json:"b,optional"`
|
||||||
|
C string `json:"c,optional=B"`
|
||||||
|
D string `json:"d,optional=b"`
|
||||||
|
}
|
||||||
|
if assert.NoError(t, Load(tmpfile, &val)) {
|
||||||
|
assert.Equal(t, "foo", val.A)
|
||||||
|
assert.Equal(t, 1, val.B)
|
||||||
|
assert.Equal(t, "FOO", val.C)
|
||||||
|
assert.Equal(t, "abcd", val.D)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfigJsonCanonical(t *testing.T) {
|
func TestConfigJsonCanonical(t *testing.T) {
|
||||||
text := []byte(`{"a": "foo", "B": "bar"}`)
|
text := []byte(`{"a": "foo", "B": "bar"}`)
|
||||||
|
|
||||||
|
|||||||
@@ -930,3 +930,13 @@ func TestUnmarshalJsonArray(t *testing.T) {
|
|||||||
assert.Equal(t, "kevin", v[0].Name)
|
assert.Equal(t, "kevin", v[0].Name)
|
||||||
assert.Equal(t, 18, v[0].Age)
|
assert.Equal(t, 18, v[0].Age)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalJsonBytesError(t *testing.T) {
|
||||||
|
var v []struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Age int `json:"age"`
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Error(t, UnmarshalJsonBytes([]byte((``)), &v))
|
||||||
|
assert.Error(t, UnmarshalJsonReader(strings.NewReader(``), &v))
|
||||||
|
}
|
||||||
|
|||||||
@@ -372,6 +372,26 @@ func (u *Unmarshaler) parseOptionsWithContext(field reflect.StructField, m Value
|
|||||||
return key, nil, nil
|
return key, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if u.opts.canonicalKey != nil {
|
||||||
|
key = u.opts.canonicalKey(key)
|
||||||
|
|
||||||
|
if len(options.OptionalDep) > 0 {
|
||||||
|
// need to create a new fieldOption, because the original one is shared through cache.
|
||||||
|
options = &fieldOptions{
|
||||||
|
fieldOptionsWithContext: fieldOptionsWithContext{
|
||||||
|
Inherit: options.Inherit,
|
||||||
|
FromString: options.FromString,
|
||||||
|
Optional: options.Optional,
|
||||||
|
Options: options.Options,
|
||||||
|
Default: options.Default,
|
||||||
|
EnvVar: options.EnvVar,
|
||||||
|
Range: options.Range,
|
||||||
|
},
|
||||||
|
OptionalDep: u.opts.canonicalKey(options.OptionalDep),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
optsWithContext, err := options.toOptionsWithContext(key, m, fullName)
|
optsWithContext, err := options.toOptionsWithContext(key, m, fullName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
|
|||||||
@@ -77,6 +77,26 @@ func TestUnmarshalWithoutTagNameWithCanonicalKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalWithoutTagNameWithCanonicalKeyOptionalDep(t *testing.T) {
|
||||||
|
type inner struct {
|
||||||
|
FirstName string `key:",optional"`
|
||||||
|
LastName string `key:",optional=FirstName"`
|
||||||
|
}
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"firstname": "go",
|
||||||
|
"lastname": "zero",
|
||||||
|
}
|
||||||
|
|
||||||
|
var in inner
|
||||||
|
unmarshaler := NewUnmarshaler(defaultKeyName, WithCanonicalKeyFunc(func(s string) string {
|
||||||
|
return strings.ToLower(s)
|
||||||
|
}))
|
||||||
|
if assert.NoError(t, unmarshaler.Unmarshal(m, &in)) {
|
||||||
|
assert.Equal(t, "go", in.FirstName)
|
||||||
|
assert.Equal(t, "zero", in.LastName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnmarshalBool(t *testing.T) {
|
func TestUnmarshalBool(t *testing.T) {
|
||||||
type inner struct {
|
type inner struct {
|
||||||
True bool `key:"yes"`
|
True bool `key:"yes"`
|
||||||
@@ -1099,6 +1119,66 @@ func TestUnmarshalStructOptionalDependsNotEnoughValue(t *testing.T) {
|
|||||||
assert.Error(t, UnmarshalKey(m, &in))
|
assert.Error(t, UnmarshalKey(m, &in))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalStructOptionalDependsMoreValues(t *testing.T) {
|
||||||
|
type address struct {
|
||||||
|
Optional string `key:",optional"`
|
||||||
|
OptionalDepends string `key:",optional=a=b"`
|
||||||
|
}
|
||||||
|
type inner struct {
|
||||||
|
Name string `key:"name"`
|
||||||
|
Address address `key:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"name": "kevin",
|
||||||
|
"address": map[string]interface{}{},
|
||||||
|
}
|
||||||
|
|
||||||
|
var in inner
|
||||||
|
assert.Error(t, UnmarshalKey(m, &in))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalStructMissing(t *testing.T) {
|
||||||
|
type address struct {
|
||||||
|
Optional string `key:",optional"`
|
||||||
|
OptionalDepends string `key:",optional=a=b"`
|
||||||
|
}
|
||||||
|
type inner struct {
|
||||||
|
Name string `key:"name"`
|
||||||
|
Address address `key:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"name": "kevin",
|
||||||
|
}
|
||||||
|
|
||||||
|
var in inner
|
||||||
|
assert.Error(t, UnmarshalKey(m, &in))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalNestedStructMissing(t *testing.T) {
|
||||||
|
type mostInner struct {
|
||||||
|
Name string `key:"name"`
|
||||||
|
}
|
||||||
|
type address struct {
|
||||||
|
Optional string `key:",optional"`
|
||||||
|
OptionalDepends string `key:",optional=a=b"`
|
||||||
|
MostInner mostInner
|
||||||
|
}
|
||||||
|
type inner struct {
|
||||||
|
Name string `key:"name"`
|
||||||
|
Address address `key:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"name": "kevin",
|
||||||
|
"address": map[string]interface{}{},
|
||||||
|
}
|
||||||
|
|
||||||
|
var in inner
|
||||||
|
assert.Error(t, UnmarshalKey(m, &in))
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnmarshalAnonymousStructOptionalDepends(t *testing.T) {
|
func TestUnmarshalAnonymousStructOptionalDepends(t *testing.T) {
|
||||||
type AnonAddress struct {
|
type AnonAddress struct {
|
||||||
City string `key:"city"`
|
City string `key:"city"`
|
||||||
@@ -1422,6 +1502,18 @@ func TestUnmarshalOptionsOptionalWrongValue(t *testing.T) {
|
|||||||
assert.Error(t, UnmarshalKey(m, &in))
|
assert.Error(t, UnmarshalKey(m, &in))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalOptionsMissingValues(t *testing.T) {
|
||||||
|
type inner struct {
|
||||||
|
Value string `key:"value,options"`
|
||||||
|
}
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"value": "first",
|
||||||
|
}
|
||||||
|
|
||||||
|
var in inner
|
||||||
|
assert.Error(t, UnmarshalKey(m, &in))
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnmarshalStringOptionsWithStringOptionsNotString(t *testing.T) {
|
func TestUnmarshalStringOptionsWithStringOptionsNotString(t *testing.T) {
|
||||||
type inner struct {
|
type inner struct {
|
||||||
Value string `key:"value,options=first|second"`
|
Value string `key:"value,options=first|second"`
|
||||||
|
|||||||
Reference in New Issue
Block a user