浏览代码

chore: add more tests (#3324)

Kevin Wan 1 年之前
父节点
当前提交
6b4d0d89c0
共有 4 个文件被更改,包括 199 次插入62 次删除
  1. 6 1
      core/mapping/unmarshaler.go
  2. 158 58
      core/mapping/unmarshaler_test.go
  3. 0 2
      core/mapping/utils.go
  4. 35 1
      core/mapping/utils_test.go

+ 6 - 1
core/mapping/unmarshaler.go

@@ -176,7 +176,12 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
 		switch dereffedBaseKind {
 		case reflect.Struct:
 			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
 			}
 

+ 158 - 58
core/mapping/unmarshaler_test.go

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

+ 0 - 2
core/mapping/utils.go

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

+ 35 - 1
core/mapping/utils_test.go

@@ -241,7 +241,8 @@ func TestValidatePtrWithZeroValue(t *testing.T) {
 
 func TestSetValueNotSettable(t *testing.T) {
 	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) {
@@ -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"))
+}