瀏覽代碼

#138 fix - without following digits; fix 1.e1

Tao Wen 8 年之前
父節點
當前提交
f705934fbf
共有 3 個文件被更改,包括 61 次插入80 次删除
  1. 29 20
      feature_iter_float.go
  2. 3 0
      feature_iter_skip_strict.go
  3. 29 60
      jsoniter_invalid_test.go

+ 29 - 20
feature_iter_float.go

@@ -4,6 +4,7 @@ import (
 	"io"
 	"math/big"
 	"strconv"
+	"strings"
 	"unsafe"
 )
 
@@ -192,16 +193,9 @@ func (iter *Iterator) readFloat32SlowPath() (ret float32) {
 	if iter.Error != nil && iter.Error != io.EOF {
 		return
 	}
-	if len(str) == 0 {
-		iter.ReportError("readFloat32SlowPath", "empty number")
-		return
-	}
-	if str[0] == '-' {
-		iter.ReportError("readFloat32SlowPath", "-- is not valid")
-		return
-	}
-	if str[len(str)-1] == '.' {
-		iter.ReportError("readFloat32SlowPath", "dot can not be last character")
+	errMsg := validateFloat(str)
+	if errMsg != "" {
+		iter.ReportError("readFloat32SlowPath", errMsg)
 		return
 	}
 	val, err := strconv.ParseFloat(str, 32)
@@ -311,16 +305,9 @@ func (iter *Iterator) readFloat64SlowPath() (ret float64) {
 	if iter.Error != nil && iter.Error != io.EOF {
 		return
 	}
-	if len(str) == 0 {
-		iter.ReportError("readFloat64SlowPath", "empty number")
-		return
-	}
-	if str[0] == '-' {
-		iter.ReportError("readFloat64SlowPath", "-- is not valid")
-		return
-	}
-	if str[len(str)-1] == '.' {
-		iter.ReportError("readFloat64SlowPath", "dot can not be last character")
+	errMsg := validateFloat(str)
+	if errMsg != "" {
+		iter.ReportError("readFloat64SlowPath", errMsg)
 		return
 	}
 	val, err := strconv.ParseFloat(str, 64)
@@ -330,3 +317,25 @@ func (iter *Iterator) readFloat64SlowPath() (ret float64) {
 	}
 	return val
 }
+
+func validateFloat(str string) string {
+	// strconv.ParseFloat is not validating `1.` or `1.e1`
+	if len(str) == 0 {
+		return "empty number"
+	}
+	if str[0] == '-' {
+		return "-- is not valid"
+	}
+	dotPos := strings.IndexByte(str, '.')
+	if dotPos != -1 {
+		if dotPos == len(str)-1 {
+			return "dot can not be last character"
+		}
+		switch str[dotPos+1] {
+		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+		default:
+			return "missing digit after dot"
+		}
+	}
+	return ""
+}

+ 3 - 0
feature_iter_skip_strict.go

@@ -36,6 +36,9 @@ func (iter *Iterator) trySkipNumber() bool {
 		default:
 			switch c {
 			case ',', ']', '}', ' ', '\t', '\n', '\r':
+				if iter.head == i {
+					return false // if - without following digits
+				}
 				iter.head = i
 				return true // must be valid
 			}

+ 29 - 60
jsoniter_invalid_test.go

@@ -68,64 +68,33 @@ func Test_invalid_array_input(t *testing.T) {
 	should.NotNil(Unmarshal(input, &obj))
 }
 
-func Test_double_negative(t *testing.T) {
-	should := require.New(t)
-	var v interface{}
-	should.NotNil(json.Unmarshal([]byte(`--2`), &v))
-	var vFloat64 float64
-	should.NotNil(UnmarshalFromString(`--2`, &vFloat64))
-	var vFloat32 float32
-	should.NotNil(UnmarshalFromString(`--2`, &vFloat32))
-	var vInt int
-	should.NotNil(UnmarshalFromString(`--2`, &vInt))
-	iter := ParseString(ConfigDefault, `--2`)
-	iter.Skip()
-	should.NotEqual(io.EOF, iter.Error)
-	should.NotNil(iter.Error)
-}
-
-func Test_leading_zero(t *testing.T) {
-	should := require.New(t)
-	var v interface{}
-	should.NotNil(json.Unmarshal([]byte(`01`), &v))
-	var vFloat64 float64
-	should.NotNil(UnmarshalFromString(`01`, &vFloat64))
-	var vFloat32 float32
-	should.NotNil(UnmarshalFromString(`01`, &vFloat32))
-	var vInt int
-	should.NotNil(UnmarshalFromString(`01`, &vInt))
-	iter := ParseString(ConfigDefault, `01,`)
-	iter.Skip()
-	should.NotEqual(io.EOF, iter.Error)
-	should.NotNil(iter.Error)
-}
-
-func Test_empty_as_number(t *testing.T) {
-	should := require.New(t)
-	iter := ParseString(ConfigDefault, `,`)
-	iter.ReadFloat64()
-	should.NotEqual(io.EOF, iter.Error)
-	should.NotNil(iter.Error)
-	iter = ParseString(ConfigDefault, `,`)
-	iter.ReadFloat32()
-	should.NotEqual(io.EOF, iter.Error)
-	should.NotNil(iter.Error)
-}
-
-func Test_missing_digit_after_dot(t *testing.T) {
-	should := require.New(t)
-	iter := ParseString(ConfigDefault, `1.,`)
-	iter.Skip()
-	should.NotEqual(io.EOF, iter.Error)
-	should.NotNil(iter.Error)
-	v := float64(0)
-	should.NotNil(json.Unmarshal([]byte(`1.`), &v))
-	iter = ParseString(ConfigDefault, `1.`)
-	iter.ReadFloat64()
-	should.NotEqual(io.EOF, iter.Error)
-	should.NotNil(iter.Error)
-	iter = ParseString(ConfigDefault, `1.`)
-	iter.ReadFloat32()
-	should.NotEqual(io.EOF, iter.Error)
-	should.NotNil(iter.Error)
+func Test_invalid_float(t *testing.T) {
+	inputs := []string{
+		`1.e1`, // dot without following digit
+		`1.`,   // dot can not be the last char
+		``,     // empty number
+		`01`,   // extra leading zero
+		`-`,    // negative without digit
+		`--`,   // double negative
+		`--2`,  // double negative
+	}
+	for _, input := range inputs {
+		t.Run(input, func(t *testing.T) {
+			should := require.New(t)
+			iter := ParseString(ConfigDefault, input+",")
+			iter.Skip()
+			should.NotEqual(io.EOF, iter.Error)
+			should.NotNil(iter.Error)
+			v := float64(0)
+			should.NotNil(json.Unmarshal([]byte(input), &v))
+			iter = ParseString(ConfigDefault, input+",")
+			iter.ReadFloat64()
+			should.NotEqual(io.EOF, iter.Error)
+			should.NotNil(iter.Error)
+			iter = ParseString(ConfigDefault, input+",")
+			iter.ReadFloat32()
+			should.NotEqual(io.EOF, iter.Error)
+			should.NotNil(iter.Error)
+		})
+	}
 }