]> Cypherpunks repositories - gostls13.git/commitdiff
strconv: fix incorrect bit size in ParseComplex; add tests
authorBen Hoyt <benhoyt@gmail.com>
Fri, 14 Aug 2020 10:58:49 +0000 (22:58 +1200)
committerRobert Griesemer <gri@golang.org>
Fri, 30 Oct 2020 00:13:25 +0000 (00:13 +0000)
In ParseComplex, the "size" passed to parseFloatPrefix should be 64 for
complex128, not 128. It still works because of how parseFloatPrefix
is forgiving about the size if it's not 32, but worth fixing anyway.

Make ParseComplex and ParseFloat return a bit size error for anything
other than 128 or 64 (for ParseComplex), or 64 or 32 (for ParseFloat).
Add "InvalidBitSize" tests for these cases.

Add tests for ParseComplex with bitSize==64: this is done in a similar
way to how the ParseFloat 32-bit tests work, re-using the tests for the
larger bit size.

Add tests for FormatComplex -- there were none before.

Fixes #40706

Change-Id: I16ddd546e5237207cc3b8c2181dd708eca42b04f
Reviewed-on: https://go-review.googlesource.com/c/go/+/248219
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Minux Ma <minux@golang.org>
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/strconv/atoc.go
src/strconv/atoc_test.go
src/strconv/atof.go
src/strconv/atof_test.go
src/strconv/ctoa_test.go [new file with mode: 0644]
src/strconv/ftoa_test.go

index 55b7c23ee7aa50614aeee7f33345046804be42f5..52cb5908b273e0dc088d2bc0c326358b4f575303 100644 (file)
@@ -40,10 +40,10 @@ func convErr(err error, s string) (syntax, range_ error) {
 // away from the largest floating point number of the given component's size,
 // ParseComplex returns err.Err = ErrRange and c = ±Inf for the respective component.
 func ParseComplex(s string, bitSize int) (complex128, error) {
-       size := 128
-       if bitSize == 64 {
-               size = 32 // complex64 uses float32 parts
+       if bitSize != 64 && bitSize != 128 {
+               return 0, bitSizeError(fnParseComplex, s, bitSize)
        }
+       size := bitSize >> 1
 
        orig := s
 
index 3aa421dd0362e78c7d8917c2cdba251a1a1ddb30..aecc09d247c54434aa59e0196a865681fbb7521e 100644 (file)
@@ -198,5 +198,27 @@ func TestParseComplex(t *testing.T) {
                if !(cmplx.IsNaN(test.out) && cmplx.IsNaN(got)) && got != test.out {
                        t.Fatalf("ParseComplex(%q, 128) = %v, %v; want %v, %v", test.in, got, err, test.out, test.err)
                }
+
+               if complex128(complex64(test.out)) == test.out {
+                       got, err := ParseComplex(test.in, 64)
+                       if !reflect.DeepEqual(err, test.err) {
+                               t.Fatalf("ParseComplex(%q, 64) = %v, %v; want %v, %v", test.in, got, err, test.out, test.err)
+                       }
+                       got64 := complex64(got)
+                       if complex128(got64) != test.out {
+                               t.Fatalf("ParseComplex(%q, 64) = %v, %v; want %v, %v", test.in, got, err, test.out, test.err)
+                       }
+               }
+       }
+}
+
+func TestParseComplexInvalidBitSize(t *testing.T) {
+       _, err := ParseComplex("1+2i", 100)
+       const want = `strconv.ParseComplex: parsing "1+2i": invalid bit size 100`
+       if err == nil {
+               t.Fatalf("got nil error, want %q", want)
+       }
+       if err.Error() != want {
+               t.Fatalf("got error %q, want %q", err, want)
        }
 }
index 9010a66ca8910bff4f3f886f3649aaab9edbcb59..a04f5621f6341259cf5da55662aa693250c35d82 100644 (file)
@@ -688,6 +688,9 @@ func atof64(s string) (f float64, n int, err error) {
 // ParseFloat recognizes the strings "NaN", and the (possibly signed) strings "Inf" and "Infinity"
 // as their respective special floating point values. It ignores case when matching.
 func ParseFloat(s string, bitSize int) (float64, error) {
+       if bitSize != 32 && bitSize != 64 {
+               return 0, bitSizeError(fnParseFloat, s, bitSize)
+       }
        f, n, err := parseFloatPrefix(s, bitSize)
        if err == nil && n != len(s) {
                return 0, syntaxError(fnParseFloat, s)
index 5a6fec8d3ba0601550a50c94cb8411cdbda4b802..cf43903506315357ef45668ed44d51d47583b982 100644 (file)
@@ -634,6 +634,17 @@ func TestRoundTrip32(t *testing.T) {
        t.Logf("tested %d float32's", count)
 }
 
+func TestParseFloatInvalidBitSize(t *testing.T) {
+       _, err := ParseFloat("3.14", 100)
+       const want = `strconv.ParseFloat: parsing "3.14": invalid bit size 100`
+       if err == nil {
+               t.Fatalf("got nil error, want %q", want)
+       }
+       if err.Error() != want {
+               t.Fatalf("got error %q, want %q", err, want)
+       }
+}
+
 func BenchmarkAtof64Decimal(b *testing.B) {
        for i := 0; i < b.N; i++ {
                ParseFloat("33909", 64)
diff --git a/src/strconv/ctoa_test.go b/src/strconv/ctoa_test.go
new file mode 100644 (file)
index 0000000..8b77898
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+       . "strconv"
+       "testing"
+)
+
+func TestFormatComplex(t *testing.T) {
+       tests := []struct {
+               c       complex128
+               fmt     byte
+               prec    int
+               bitSize int
+               out     string
+       }{
+               // a variety of signs
+               {1 + 2i, 'g', -1, 128, "(1+2i)"},
+               {3 - 4i, 'g', -1, 128, "(3-4i)"},
+               {-5 + 6i, 'g', -1, 128, "(-5+6i)"},
+               {-7 - 8i, 'g', -1, 128, "(-7-8i)"},
+
+               // test that fmt and prec are working
+               {3.14159 + 0.00123i, 'e', 3, 128, "(3.142e+00+1.230e-03i)"},
+               {3.14159 + 0.00123i, 'f', 3, 128, "(3.142+0.001i)"},
+               {3.14159 + 0.00123i, 'g', 3, 128, "(3.14+0.00123i)"},
+
+               // ensure bitSize rounding is working
+               {1.2345678901234567 + 9.876543210987654i, 'f', -1, 128, "(1.2345678901234567+9.876543210987654i)"},
+               {1.2345678901234567 + 9.876543210987654i, 'f', -1, 64, "(1.2345679+9.876543i)"},
+
+               // other cases are handled by FormatFloat tests
+       }
+       for _, test := range tests {
+               out := FormatComplex(test.c, test.fmt, test.prec, test.bitSize)
+               if out != test.out {
+                       t.Fatalf("FormatComplex(%v, %q, %d, %d) = %q; want %q",
+                               test.c, test.fmt, test.prec, test.bitSize, out, test.out)
+               }
+       }
+}
+
+func TestFormatComplexInvalidBitSize(t *testing.T) {
+       defer func() {
+               if r := recover(); r == nil {
+                       t.Fatalf("expected panic due to invalid bitSize")
+               }
+       }()
+       _ = FormatComplex(1+2i, 'g', -1, 100)
+}
index 755c986b86e4c3ef7fed82680686c8bc8b0d4203..99cca17542ffc2e74a0be94880e987a4ab7cb665 100644 (file)
@@ -212,6 +212,15 @@ func TestFtoaRandom(t *testing.T) {
        }
 }
 
+func TestFormatFloatInvalidBitSize(t *testing.T) {
+       defer func() {
+               if r := recover(); r == nil {
+                       t.Fatalf("expected panic due to invalid bitSize")
+               }
+       }()
+       _ = FormatFloat(3.14, 'g', -1, 100)
+}
+
 var ftoaBenches = []struct {
        name    string
        float   float64