diff --git a/pkg/fixedpoint/convert.go b/pkg/fixedpoint/convert.go index 6d8a54158..1d025abf1 100644 --- a/pkg/fixedpoint/convert.go +++ b/pkg/fixedpoint/convert.go @@ -347,6 +347,7 @@ func NewFromString(input string) (Value, error) { decimalCount := 0 // if is decimal, we don't need this hasScientificNotion := false + hasIChar := false scIndex := -1 for i, c := range input { if hasDecimal { @@ -365,6 +366,10 @@ func NewFromString(input string) (Value, error) { scIndex = i break } + if c == 'i' || c == 'I' { + hasIChar = true + break + } } if hasDecimal { after := input[dotIndex+1:] @@ -395,6 +400,16 @@ func NewFromString(input string) (Value, error) { return 0, err } return Value(int64(math.Trunc(v))), nil + } else if hasIChar { + if floatV, err := strconv.ParseFloat(input, 64); nil != err { + return 0, err + } else if math.IsInf(floatV, 1) { + return PosInf, nil + } else if math.IsInf(floatV, -1) { + return NegInf, nil + } else { + return 0, fmt.Errorf("fixedpoint.Value parse error, invalid input string %s", input) + } } else { v, err := strconv.ParseInt(input, 10, 64) if err != nil { diff --git a/pkg/fixedpoint/dec.go b/pkg/fixedpoint/dec.go index 1b279bdfe..2b5f3743b 100644 --- a/pkg/fixedpoint/dec.go +++ b/pkg/fixedpoint/dec.go @@ -500,7 +500,7 @@ func NewFromString(s string) (Value, error) { } r := &reader{s, 0} sign := r.getSign() - if r.matchStr("inf") { + if r.matchStrIgnoreCase("inf") { return Inf(sign), nil } coef, exp := r.getCoef() @@ -550,7 +550,7 @@ func NewFromBytes(s []byte) (Value, error) { } r := &readerBytes{s, 0} sign := r.getSign() - if r.matchStr("inf") { + if r.matchStrIgnoreCase("inf") { return Inf(sign), nil } coef, exp := r.getCoef() @@ -631,13 +631,18 @@ func (r *readerBytes) matchDigit() bool { return false } -func (r *readerBytes) matchStr(pre string) bool { - for i, c := range r.s[r.i:] { +func (r *readerBytes) matchStrIgnoreCase(pre string) bool { + pre = strings.ToLower(pre) + boundary := r.i + len(pre) + if boundary > len(r.s) { + return false + } + for i, c := range bytes.ToLower(r.s[r.i:boundary]) { if pre[i] != c { return false } } - r.i += len(pre) + r.i = boundary return true } @@ -745,9 +750,15 @@ func (r *reader) matchDigit() bool { return false } -func (r *reader) matchStr(pre string) bool { - if strings.HasPrefix(r.s[r.i:], pre) { - r.i += len(pre) +func (r *reader) matchStrIgnoreCase(pre string) bool { + boundary := r.i + len(pre) + if boundary > len(r.s) { + return false + } + data := strings.ToLower(r.s[r.i:boundary]) + pre = strings.ToLower(pre) + if data == pre { + r.i = boundary return true } return false diff --git a/pkg/fixedpoint/dec_test.go b/pkg/fixedpoint/dec_test.go index 269904c1b..8c72582f6 100644 --- a/pkg/fixedpoint/dec_test.go +++ b/pkg/fixedpoint/dec_test.go @@ -138,6 +138,15 @@ func TestFromString(t *testing.T) { assert.Equal(t, Zero, f) f = MustNewFromString("") assert.Equal(t, Zero, f) + + for _, s := range []string{"inf", "Inf", "INF", "iNF"} { + f = MustNewFromString(s) + assert.Equal(t, PosInf, f) + f = MustNewFromString("+" + s) + assert.Equal(t, PosInf, f) + f = MustNewFromString("-" + s) + assert.Equal(t, NegInf, f) + } } func TestJson(t *testing.T) { @@ -177,6 +186,10 @@ func TestJson(t *testing.T) { _ = json.Unmarshal([]byte("0.000062"), &q) assert.Equal(t, "0.00006194", q.Sub(p).String()) + assert.NoError(t, json.Unmarshal([]byte(`"inf"`), &p)) + assert.NoError(t, json.Unmarshal([]byte(`"+Inf"`), &q)) + assert.Equal(t, PosInf, p) + assert.Equal(t, p, q) } func TestYaml(t *testing.T) { @@ -216,6 +229,10 @@ func TestYaml(t *testing.T) { _ = yaml.Unmarshal([]byte("0.000062"), &q) assert.Equal(t, "0.00006194", q.Sub(p).String()) + assert.NoError(t, json.Unmarshal([]byte(`"inf"`), &p)) + assert.NoError(t, json.Unmarshal([]byte(`"+Inf"`), &q)) + assert.Equal(t, PosInf, p) + assert.Equal(t, p, q) } func TestNumFractionalDigits(t *testing.T) {