Browse Source

Do not accept plain ints into time.Duration.

It used to work in v2, but that's very error prone as it's easy to say,
for example, 10 meaning 10 seconds, but it's really 10 nanoseconds.

Closes #200.
Gustavo Niemeyer 7 years ago
parent
commit
9e322716c2
2 changed files with 14 additions and 4 deletions
  1. 7 4
      decode.go
  2. 7 0
      decode_test.go

+ 7 - 4
decode.go

@@ -555,24 +555,27 @@ func (d *decoder) scalar(n *Node, out reflect.Value) bool {
 		}
 		return true
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		// This used to work in v2, but it's very unfriendly.
+		isDuration := out.Type() == durationType
+
 		switch resolved := resolved.(type) {
 		case int:
-			if !out.OverflowInt(int64(resolved)) {
+			if !isDuration && !out.OverflowInt(int64(resolved)) {
 				out.SetInt(int64(resolved))
 				return true
 			}
 		case int64:
-			if !out.OverflowInt(resolved) {
+			if !isDuration && !out.OverflowInt(resolved) {
 				out.SetInt(resolved)
 				return true
 			}
 		case uint64:
-			if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
+			if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
 				out.SetInt(int64(resolved))
 				return true
 			}
 		case float64:
-			if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
+			if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
 				out.SetInt(int64(resolved))
 				return true
 			}

+ 7 - 0
decode_test.go

@@ -809,6 +809,13 @@ func (s *S) TestUnmarshalNaN(c *C) {
 	c.Assert(math.IsNaN(value["notanum"].(float64)), Equals, true)
 }
 
+func (s *S) TestUnmarshalDurationInt(c *C) {
+	// Don't accept plain ints as durations as it's unclear (issue #200).
+	var d time.Duration
+	err := yaml.Unmarshal([]byte("123"), &d)
+	c.Assert(err, ErrorMatches, "(?s).* line 1: cannot unmarshal !!int `123` into time.Duration")
+}
+
 var unmarshalErrorTests = []struct {
 	data, error string
 }{