]> Cypherpunks repositories - gostls13.git/commitdiff
test: generate tests for arithmetic on narrow types
authorKeith Randall <khr@golang.org>
Fri, 16 Jan 2015 05:02:51 +0000 (21:02 -0800)
committerKeith Randall <khr@golang.org>
Sat, 17 Jan 2015 21:00:15 +0000 (21:00 +0000)
Fixes #9607
Related to #9604
Inadvertently found #9609

Change-Id: I8a8ddf84ac72d3e18986fd8e9288734459f3f174
Reviewed-on: https://go-review.googlesource.com/2962
Reviewed-by: Minux Ma <minux@golang.org>
test/fixedbugs/issue9604b.go [new file with mode: 0644]

diff --git a/test/fixedbugs/issue9604b.go b/test/fixedbugs/issue9604b.go
new file mode 100644 (file)
index 0000000..ebbd205
--- /dev/null
@@ -0,0 +1,177 @@
+// runoutput
+
+// Copyright 2015 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 main
+
+import (
+       "fmt"
+       "math/big"
+       "unsafe"
+)
+
+var one = big.NewInt(1)
+
+type _type struct {
+       name   string
+       bits   uint
+       signed bool
+}
+
+// testvalues returns a list of all test values for this type.
+func (t *_type) testvalues() []*big.Int {
+       var a []*big.Int
+
+       a = append(a, big.NewInt(0))
+       a = append(a, big.NewInt(1))
+       a = append(a, big.NewInt(2))
+       if t.signed {
+               a = append(a, big.NewInt(-1))
+               a = append(a, big.NewInt(-2))
+               r := big.NewInt(1)
+               a = append(a, r.Lsh(r, t.bits-1).Sub(r, big.NewInt(1)))
+               r = big.NewInt(1)
+               a = append(a, r.Lsh(r, t.bits-1).Sub(r, big.NewInt(2)))
+               r = big.NewInt(1)
+               a = append(a, r.Lsh(r, t.bits-1).Neg(r))
+               r = big.NewInt(1)
+               a = append(a, r.Lsh(r, t.bits-1).Neg(r).Add(r, big.NewInt(1)))
+       } else {
+               r := big.NewInt(1)
+               a = append(a, r.Lsh(r, t.bits).Sub(r, big.NewInt(1)))
+               r = big.NewInt(1)
+               a = append(a, r.Lsh(r, t.bits).Sub(r, big.NewInt(2)))
+       }
+       return a
+}
+
+// trunc truncates a value to the range of the given type.
+func (t *_type) trunc(x *big.Int) *big.Int {
+       r := new(big.Int)
+       m := new(big.Int)
+       m.Lsh(one, t.bits)
+       m.Sub(m, one)
+       r.And(x, m)
+       if t.signed && r.Bit(int(t.bits)-1) == 1 {
+               m.Neg(one)
+               m.Lsh(m, t.bits)
+               r.Or(r, m)
+       }
+       return r
+}
+
+var types = []_type{
+       _type{"byte", 8, false},
+       _type{"int8", 8, true},
+       _type{"uint8", 8, false},
+       _type{"rune", 32, true},
+       _type{"int16", 16, true},
+       _type{"uint16", 16, false},
+       _type{"int32", 32, true},
+       _type{"uint32", 32, false},
+       _type{"int64", 64, true},
+       _type{"uint64", 64, false},
+       _type{"int", 8 * uint(unsafe.Sizeof(int(0))), true},
+       _type{"uint", 8 * uint(unsafe.Sizeof(uint(0))), false},
+       _type{"uintptr", 8 * uint(unsafe.Sizeof((*byte)(nil))), false},
+}
+
+type binop struct {
+       name string
+       eval func(x, y *big.Int) *big.Int
+}
+
+var binops = []binop{
+       binop{"+", func(x, y *big.Int) *big.Int { return new(big.Int).Add(x, y) }},
+       binop{"-", func(x, y *big.Int) *big.Int { return new(big.Int).Sub(x, y) }},
+       binop{"*", func(x, y *big.Int) *big.Int { return new(big.Int).Mul(x, y) }},
+       binop{"/", func(x, y *big.Int) *big.Int { return new(big.Int).Quo(x, y) }},
+       binop{"%", func(x, y *big.Int) *big.Int { return new(big.Int).Rem(x, y) }},
+       binop{"&", func(x, y *big.Int) *big.Int { return new(big.Int).And(x, y) }},
+       binop{"|", func(x, y *big.Int) *big.Int { return new(big.Int).Or(x, y) }},
+       binop{"^", func(x, y *big.Int) *big.Int { return new(big.Int).Xor(x, y) }},
+       binop{"&^", func(x, y *big.Int) *big.Int { return new(big.Int).AndNot(x, y) }},
+}
+
+type unop struct {
+       name string
+       eval func(x *big.Int) *big.Int
+}
+
+var unops = []unop{
+       unop{"+", func(x *big.Int) *big.Int { return new(big.Int).Set(x) }},
+       unop{"-", func(x *big.Int) *big.Int { return new(big.Int).Neg(x) }},
+       unop{"^", func(x *big.Int) *big.Int { return new(big.Int).Not(x) }},
+}
+
+type shiftop struct {
+       name string
+       eval func(x *big.Int, i uint) *big.Int
+}
+
+var shiftops = []shiftop{
+       shiftop{"<<", func(x *big.Int, i uint) *big.Int { return new(big.Int).Lsh(x, i) }},
+       shiftop{">>", func(x *big.Int, i uint) *big.Int { return new(big.Int).Rsh(x, i) }},
+}
+
+// valname returns the name of n as can be used as part of a variable name.
+func valname(n *big.Int) string {
+       s := fmt.Sprintf("%d", n)
+       if s[0] == '-' {
+               s = "neg" + s[1:]
+       }
+       return s
+}
+
+func main() {
+       fmt.Println("package main")
+
+       // We make variables to hold all the different values we'd like to use.
+       // We use global variables to prevent any constant folding.
+       for _, t := range types {
+               for _, n := range t.testvalues() {
+                       fmt.Printf("var %s_%s %s = %d\n", t.name, valname(n), t.name, n)
+               }
+       }
+
+       fmt.Println("func main() {")
+
+       for _, t := range types {
+               // test binary ops
+               for _, op := range binops {
+                       for _, x := range t.testvalues() {
+                               for _, y := range t.testvalues() {
+                                       if (op.name == "/" || op.name == "%") && y.Sign() == 0 {
+                                               continue
+                                       }
+                                       r := t.trunc(op.eval(x, y))
+                                       eqn := fmt.Sprintf("%s_%s %s %s_%s != %d", t.name, valname(x), op.name, t.name, valname(y), r)
+                                       fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn)
+                               }
+                       }
+               }
+               // test unary ops
+               for _, op := range unops {
+                       for _, x := range t.testvalues() {
+                               r := t.trunc(op.eval(x))
+                               eqn := fmt.Sprintf("%s %s_%s != %d", op.name, t.name, valname(x), r)
+                               fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn)
+                       }
+               }
+               // test shifts
+               for _, op := range shiftops {
+                       for _, x := range t.testvalues() {
+
+                               for _, i := range []uint{0, 1, t.bits - 2, t.bits - 1, t.bits, t.bits + 1} {
+                                       r := t.trunc(op.eval(x, i))
+                                       eqn := fmt.Sprintf("%s_%s %s %d != %d", t.name, valname(x), op.name, i, r)
+                                       fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn)
+                               }
+                       }
+               }
+       }
+
+       fmt.Println("}")
+}