go/test/map.go
Brad Fitzpatrick 5e21cb7865 test: fix flaky NaN-key map complexity test
Don't measure wall time in map.go. Keep it portable
and only test NaN, but not time.

Move time tests to mapnan.go and only measure user CPU time,
not wall time. It builds on Darwin and Linux, the primary
platforms where people hack on the runtime & in particular
maps. The runtime is shared, though, so we don't need it to
run on all of the platforms.

Fixes flaky build failures like:
http://build.golang.org/log/ba67eceefdeaa1142cb6c990a62fa3ffd8fd73f8

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/8479043
2013-04-07 11:56:15 -07:00

684 lines
15 KiB
Go

// run
// Copyright 2009 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.
// Test maps, almost exhaustively.
// NaN complexity test is in mapnan.go.
package main
import (
"fmt"
"math"
"strconv"
)
const count = 100
func P(a []string) string {
s := "{"
for i := 0; i < len(a); i++ {
if i > 0 {
s += ","
}
s += `"` + a[i] + `"`
}
s += "}"
return s
}
func main() {
testbasic()
testfloat()
testnan()
}
func testbasic() {
// Test a map literal.
mlit := map[string]int{"0": 0, "1": 1, "2": 2, "3": 3, "4": 4}
for i := 0; i < len(mlit); i++ {
s := string([]byte{byte(i) + '0'})
if mlit[s] != i {
panic(fmt.Sprintf("mlit[%s] = %d\n", s, mlit[s]))
}
}
mib := make(map[int]bool)
mii := make(map[int]int)
mfi := make(map[float32]int)
mif := make(map[int]float32)
msi := make(map[string]int)
mis := make(map[int]string)
mss := make(map[string]string)
mspa := make(map[string][]string)
// BUG need an interface map both ways too
type T struct {
i int64 // can't use string here; struct values are only compared at the top level
f float32
}
mipT := make(map[int]*T)
mpTi := make(map[*T]int)
mit := make(map[int]T)
// mti := make(map[T] int)
type M map[int]int
mipM := make(map[int]M)
var apT [2 * count]*T
for i := 0; i < count; i++ {
s := strconv.Itoa(i)
s10 := strconv.Itoa(i * 10)
f := float32(i)
t := T{int64(i), f}
apT[i] = new(T)
apT[i].i = int64(i)
apT[i].f = f
apT[2*i] = new(T) // need twice as many entries as we use, for the nonexistence check
apT[2*i].i = int64(i)
apT[2*i].f = f
m := M{i: i + 1}
mib[i] = (i != 0)
mii[i] = 10 * i
mfi[float32(i)] = 10 * i
mif[i] = 10.0 * f
mis[i] = s
msi[s] = i
mss[s] = s10
mss[s] = s10
as := make([]string, 2)
as[0] = s10
as[1] = s10
mspa[s] = as
mipT[i] = apT[i]
mpTi[apT[i]] = i
mipM[i] = m
mit[i] = t
// mti[t] = i
}
// test len
if len(mib) != count {
panic(fmt.Sprintf("len(mib) = %d\n", len(mib)))
}
if len(mii) != count {
panic(fmt.Sprintf("len(mii) = %d\n", len(mii)))
}
if len(mfi) != count {
panic(fmt.Sprintf("len(mfi) = %d\n", len(mfi)))
}
if len(mif) != count {
panic(fmt.Sprintf("len(mif) = %d\n", len(mif)))
}
if len(msi) != count {
panic(fmt.Sprintf("len(msi) = %d\n", len(msi)))
}
if len(mis) != count {
panic(fmt.Sprintf("len(mis) = %d\n", len(mis)))
}
if len(mss) != count {
panic(fmt.Sprintf("len(mss) = %d\n", len(mss)))
}
if len(mspa) != count {
panic(fmt.Sprintf("len(mspa) = %d\n", len(mspa)))
}
if len(mipT) != count {
panic(fmt.Sprintf("len(mipT) = %d\n", len(mipT)))
}
if len(mpTi) != count {
panic(fmt.Sprintf("len(mpTi) = %d\n", len(mpTi)))
}
// if len(mti) != count {
// panic(fmt.Sprintf("len(mti) = %d\n", len(mti)))
// }
if len(mipM) != count {
panic(fmt.Sprintf("len(mipM) = %d\n", len(mipM)))
}
// if len(mti) != count {
// panic(fmt.Sprintf("len(mti) = %d\n", len(mti)))
// }
if len(mit) != count {
panic(fmt.Sprintf("len(mit) = %d\n", len(mit)))
}
// test construction directly
for i := 0; i < count; i++ {
s := strconv.Itoa(i)
s10 := strconv.Itoa(i * 10)
f := float32(i)
// BUG m := M(i, i+1)
if mib[i] != (i != 0) {
panic(fmt.Sprintf("mib[%d] = %t\n", i, mib[i]))
}
if mii[i] != 10*i {
panic(fmt.Sprintf("mii[%d] = %d\n", i, mii[i]))
}
if mfi[f] != 10*i {
panic(fmt.Sprintf("mfi[%d] = %d\n", i, mfi[f]))
}
if mif[i] != 10.0*f {
panic(fmt.Sprintf("mif[%d] = %g\n", i, mif[i]))
}
if mis[i] != s {
panic(fmt.Sprintf("mis[%d] = %s\n", i, mis[i]))
}
if msi[s] != i {
panic(fmt.Sprintf("msi[%s] = %d\n", s, msi[s]))
}
if mss[s] != s10 {
panic(fmt.Sprintf("mss[%s] = %g\n", s, mss[s]))
}
for j := 0; j < len(mspa[s]); j++ {
if mspa[s][j] != s10 {
panic(fmt.Sprintf("mspa[%s][%d] = %s\n", s, j, mspa[s][j]))
}
}
if mipT[i].i != int64(i) || mipT[i].f != f {
panic(fmt.Sprintf("mipT[%d] = %v\n", i, mipT[i]))
}
if mpTi[apT[i]] != i {
panic(fmt.Sprintf("mpTi[apT[%d]] = %d\n", i, mpTi[apT[i]]))
}
// if(mti[t] != i) {
// panic(fmt.Sprintf("mti[%s] = %s\n", s, mti[t]))
// }
if mipM[i][i] != i+1 {
panic(fmt.Sprintf("mipM[%d][%d] = %d\n", i, i, mipM[i][i]))
}
// if(mti[t] != i) {
// panic(fmt.Sprintf("mti[%v] = %d\n", t, mti[t]))
// }
if mit[i].i != int64(i) || mit[i].f != f {
panic(fmt.Sprintf("mit[%d] = {%d %g}\n", i, mit[i].i, mit[i].f))
}
}
// test existence with tuple check
// failed lookups yield a false value for the boolean.
for i := 0; i < count; i++ {
s := strconv.Itoa(i)
f := float32(i)
{
_, b := mib[i]
if !b {
panic(fmt.Sprintf("tuple existence decl: mib[%d]\n", i))
}
_, b = mib[i]
if !b {
panic(fmt.Sprintf("tuple existence assign: mib[%d]\n", i))
}
}
{
_, b := mii[i]
if !b {
panic(fmt.Sprintf("tuple existence decl: mii[%d]\n", i))
}
_, b = mii[i]
if !b {
panic(fmt.Sprintf("tuple existence assign: mii[%d]\n", i))
}
}
{
_, b := mfi[f]
if !b {
panic(fmt.Sprintf("tuple existence decl: mfi[%d]\n", i))
}
_, b = mfi[f]
if !b {
panic(fmt.Sprintf("tuple existence assign: mfi[%d]\n", i))
}
}
{
_, b := mif[i]
if !b {
panic(fmt.Sprintf("tuple existence decl: mif[%d]\n", i))
}
_, b = mif[i]
if !b {
panic(fmt.Sprintf("tuple existence assign: mif[%d]\n", i))
}
}
{
_, b := mis[i]
if !b {
panic(fmt.Sprintf("tuple existence decl: mis[%d]\n", i))
}
_, b = mis[i]
if !b {
panic(fmt.Sprintf("tuple existence assign: mis[%d]\n", i))
}
}
{
_, b := msi[s]
if !b {
panic(fmt.Sprintf("tuple existence decl: msi[%d]\n", i))
}
_, b = msi[s]
if !b {
panic(fmt.Sprintf("tuple existence assign: msi[%d]\n", i))
}
}
{
_, b := mss[s]
if !b {
panic(fmt.Sprintf("tuple existence decl: mss[%d]\n", i))
}
_, b = mss[s]
if !b {
panic(fmt.Sprintf("tuple existence assign: mss[%d]\n", i))
}
}
{
_, b := mspa[s]
if !b {
panic(fmt.Sprintf("tuple existence decl: mspa[%d]\n", i))
}
_, b = mspa[s]
if !b {
panic(fmt.Sprintf("tuple existence assign: mspa[%d]\n", i))
}
}
{
_, b := mipT[i]
if !b {
panic(fmt.Sprintf("tuple existence decl: mipT[%d]\n", i))
}
_, b = mipT[i]
if !b {
panic(fmt.Sprintf("tuple existence assign: mipT[%d]\n", i))
}
}
{
_, b := mpTi[apT[i]]
if !b {
panic(fmt.Sprintf("tuple existence decl: mpTi[apT[%d]]\n", i))
}
_, b = mpTi[apT[i]]
if !b {
panic(fmt.Sprintf("tuple existence assign: mpTi[apT[%d]]\n", i))
}
}
{
_, b := mipM[i]
if !b {
panic(fmt.Sprintf("tuple existence decl: mipM[%d]\n", i))
}
_, b = mipM[i]
if !b {
panic(fmt.Sprintf("tuple existence assign: mipM[%d]\n", i))
}
}
{
_, b := mit[i]
if !b {
panic(fmt.Sprintf("tuple existence decl: mit[%d]\n", i))
}
_, b = mit[i]
if !b {
panic(fmt.Sprintf("tuple existence assign: mit[%d]\n", i))
}
}
// {
// _, b := mti[t]
// if !b {
// panic(fmt.Sprintf("tuple existence decl: mti[%d]\n", i))
// }
// _, b = mti[t]
// if !b {
// panic(fmt.Sprintf("tuple existence assign: mti[%d]\n", i))
// }
// }
}
// test nonexistence with tuple check
// failed lookups yield a false value for the boolean.
for i := count; i < 2*count; i++ {
s := strconv.Itoa(i)
f := float32(i)
{
_, b := mib[i]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mib[%d]", i))
}
_, b = mib[i]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mib[%d]", i))
}
}
{
_, b := mii[i]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mii[%d]", i))
}
_, b = mii[i]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mii[%d]", i))
}
}
{
_, b := mfi[f]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mfi[%d]", i))
}
_, b = mfi[f]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mfi[%d]", i))
}
}
{
_, b := mif[i]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mif[%d]", i))
}
_, b = mif[i]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mif[%d]", i))
}
}
{
_, b := mis[i]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mis[%d]", i))
}
_, b = mis[i]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mis[%d]", i))
}
}
{
_, b := msi[s]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: msi[%d]", i))
}
_, b = msi[s]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: msi[%d]", i))
}
}
{
_, b := mss[s]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mss[%d]", i))
}
_, b = mss[s]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mss[%d]", i))
}
}
{
_, b := mspa[s]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mspa[%d]", i))
}
_, b = mspa[s]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mspa[%d]", i))
}
}
{
_, b := mipT[i]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mipT[%d]", i))
}
_, b = mipT[i]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mipT[%d]", i))
}
}
{
_, b := mpTi[apT[i]]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mpTi[apt[%d]]", i))
}
_, b = mpTi[apT[i]]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mpTi[apT[%d]]", i))
}
}
{
_, b := mipM[i]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mipM[%d]", i))
}
_, b = mipM[i]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mipM[%d]", i))
}
}
// {
// _, b := mti[t]
// if b {
// panic(fmt.Sprintf("tuple nonexistence decl: mti[%d]", i))
// }
// _, b = mti[t]
// if b {
// panic(fmt.Sprintf("tuple nonexistence assign: mti[%d]", i))
// }
// }
{
_, b := mit[i]
if b {
panic(fmt.Sprintf("tuple nonexistence decl: mit[%d]", i))
}
_, b = mit[i]
if b {
panic(fmt.Sprintf("tuple nonexistence assign: mit[%d]", i))
}
}
}
// tests for structured map element updates
for i := 0; i < count; i++ {
s := strconv.Itoa(i)
mspa[s][i%2] = "deleted"
if mspa[s][i%2] != "deleted" {
panic(fmt.Sprintf("update mspa[%s][%d] = %s\n", s, i%2, mspa[s][i%2]))
}
mipT[i].i += 1
if mipT[i].i != int64(i)+1 {
panic(fmt.Sprintf("update mipT[%d].i = %d\n", i, mipT[i].i))
}
mipT[i].f = float32(i + 1)
if mipT[i].f != float32(i+1) {
panic(fmt.Sprintf("update mipT[%d].f = %g\n", i, mipT[i].f))
}
mipM[i][i]++
if mipM[i][i] != (i+1)+1 {
panic(fmt.Sprintf("update mipM[%d][%d] = %d\n", i, i, mipM[i][i]))
}
}
// test range on nil map
var mnil map[string]int
for _, _ = range mnil {
panic("range mnil")
}
}
func testfloat() {
// Test floating point numbers in maps.
// Two map keys refer to the same entry if the keys are ==.
// The special cases, then, are that +0 == -0 and that NaN != NaN.
{
var (
pz = float32(0)
nz = math.Float32frombits(1 << 31)
nana = float32(math.NaN())
nanb = math.Float32frombits(math.Float32bits(nana) ^ 2)
)
m := map[float32]string{
pz: "+0",
nana: "NaN",
nanb: "NaN",
}
if m[pz] != "+0" {
panic(fmt.Sprintln("float32 map cannot read back m[+0]:", m[pz]))
}
if m[nz] != "+0" {
fmt.Sprintln("float32 map does not treat", pz, "and", nz, "as equal for read")
panic(fmt.Sprintln("float32 map does not treat -0 and +0 as equal for read"))
}
m[nz] = "-0"
if m[pz] != "-0" {
panic(fmt.Sprintln("float32 map does not treat -0 and +0 as equal for write"))
}
if _, ok := m[nana]; ok {
panic(fmt.Sprintln("float32 map allows NaN lookup (a)"))
}
if _, ok := m[nanb]; ok {
panic(fmt.Sprintln("float32 map allows NaN lookup (b)"))
}
if len(m) != 3 {
panic(fmt.Sprintln("float32 map should have 3 entries:", m))
}
m[nana] = "NaN"
m[nanb] = "NaN"
if len(m) != 5 {
panic(fmt.Sprintln("float32 map should have 5 entries:", m))
}
}
{
var (
pz = float64(0)
nz = math.Float64frombits(1 << 63)
nana = float64(math.NaN())
nanb = math.Float64frombits(math.Float64bits(nana) ^ 2)
)
m := map[float64]string{
pz: "+0",
nana: "NaN",
nanb: "NaN",
}
if m[nz] != "+0" {
panic(fmt.Sprintln("float64 map does not treat -0 and +0 as equal for read"))
}
m[nz] = "-0"
if m[pz] != "-0" {
panic(fmt.Sprintln("float64 map does not treat -0 and +0 as equal for write"))
}
if _, ok := m[nana]; ok {
panic(fmt.Sprintln("float64 map allows NaN lookup (a)"))
}
if _, ok := m[nanb]; ok {
panic(fmt.Sprintln("float64 map allows NaN lookup (b)"))
}
if len(m) != 3 {
panic(fmt.Sprintln("float64 map should have 3 entries:", m))
}
m[nana] = "NaN"
m[nanb] = "NaN"
if len(m) != 5 {
panic(fmt.Sprintln("float64 map should have 5 entries:", m))
}
}
{
var (
pz = complex64(0)
nz = complex(0, math.Float32frombits(1<<31))
nana = complex(5, float32(math.NaN()))
nanb = complex(5, math.Float32frombits(math.Float32bits(float32(math.NaN()))^2))
)
m := map[complex64]string{
pz: "+0",
nana: "NaN",
nanb: "NaN",
}
if m[nz] != "+0" {
panic(fmt.Sprintln("complex64 map does not treat -0 and +0 as equal for read"))
}
m[nz] = "-0"
if m[pz] != "-0" {
panic(fmt.Sprintln("complex64 map does not treat -0 and +0 as equal for write"))
}
if _, ok := m[nana]; ok {
panic(fmt.Sprintln("complex64 map allows NaN lookup (a)"))
}
if _, ok := m[nanb]; ok {
panic(fmt.Sprintln("complex64 map allows NaN lookup (b)"))
}
if len(m) != 3 {
panic(fmt.Sprintln("complex64 map should have 3 entries:", m))
}
m[nana] = "NaN"
m[nanb] = "NaN"
if len(m) != 5 {
panic(fmt.Sprintln("complex64 map should have 5 entries:", m))
}
}
{
var (
pz = complex128(0)
nz = complex(0, math.Float64frombits(1<<63))
nana = complex(5, float64(math.NaN()))
nanb = complex(5, math.Float64frombits(math.Float64bits(float64(math.NaN()))^2))
)
m := map[complex128]string{
pz: "+0",
nana: "NaN",
nanb: "NaN",
}
if m[nz] != "+0" {
panic(fmt.Sprintln("complex128 map does not treat -0 and +0 as equal for read"))
}
m[nz] = "-0"
if m[pz] != "-0" {
panic(fmt.Sprintln("complex128 map does not treat -0 and +0 as equal for write"))
}
if _, ok := m[nana]; ok {
panic(fmt.Sprintln("complex128 map allows NaN lookup (a)"))
}
if _, ok := m[nanb]; ok {
panic(fmt.Sprintln("complex128 map allows NaN lookup (b)"))
}
if len(m) != 3 {
panic(fmt.Sprintln("complex128 map should have 3 entries:", m))
}
m[nana] = "NaN"
m[nanb] = "NaN"
if len(m) != 5 {
panic(fmt.Sprintln("complex128 map should have 5 entries:", m))
}
}
}
func testnan() {
n := 500
m := map[float64]int{}
nan := math.NaN()
for i := 0; i < n; i++ {
m[nan] = 1
}
if len(m) != n {
panic("wrong size map after nan insertion")
}
iters := 0
for k, v := range m {
iters++
if !math.IsNaN(k) {
panic("not NaN")
}
if v != 1 {
panic("wrong value")
}
}
if iters != n {
panic("wrong number of nan range iters")
}
}