Source file src/maps/maps_test.go

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package maps
     6  
     7  import (
     8  	"math"
     9  	"strconv"
    10  	"testing"
    11  )
    12  
    13  var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16}
    14  var m2 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"}
    15  
    16  func TestEqual(t *testing.T) {
    17  	if !Equal(m1, m1) {
    18  		t.Errorf("Equal(%v, %v) = false, want true", m1, m1)
    19  	}
    20  	if Equal(m1, (map[int]int)(nil)) {
    21  		t.Errorf("Equal(%v, nil) = true, want false", m1)
    22  	}
    23  	if Equal((map[int]int)(nil), m1) {
    24  		t.Errorf("Equal(nil, %v) = true, want false", m1)
    25  	}
    26  	if !Equal[map[int]int, map[int]int](nil, nil) {
    27  		t.Error("Equal(nil, nil) = false, want true")
    28  	}
    29  	if ms := map[int]int{1: 2}; Equal(m1, ms) {
    30  		t.Errorf("Equal(%v, %v) = true, want false", m1, ms)
    31  	}
    32  
    33  	// Comparing NaN for equality is expected to fail.
    34  	mf := map[int]float64{1: 0, 2: math.NaN()}
    35  	if Equal(mf, mf) {
    36  		t.Errorf("Equal(%v, %v) = true, want false", mf, mf)
    37  	}
    38  }
    39  
    40  // equal is simply ==.
    41  func equal[T comparable](v1, v2 T) bool {
    42  	return v1 == v2
    43  }
    44  
    45  // equalNaN is like == except that all NaNs are equal.
    46  func equalNaN[T comparable](v1, v2 T) bool {
    47  	isNaN := func(f T) bool { return f != f }
    48  	return v1 == v2 || (isNaN(v1) && isNaN(v2))
    49  }
    50  
    51  // equalStr compares ints and strings.
    52  func equalIntStr(v1 int, v2 string) bool {
    53  	return strconv.Itoa(v1) == v2
    54  }
    55  
    56  func TestEqualFunc(t *testing.T) {
    57  	if !EqualFunc(m1, m1, equal[int]) {
    58  		t.Errorf("EqualFunc(%v, %v, equal) = false, want true", m1, m1)
    59  	}
    60  	if EqualFunc(m1, (map[int]int)(nil), equal[int]) {
    61  		t.Errorf("EqualFunc(%v, nil, equal) = true, want false", m1)
    62  	}
    63  	if EqualFunc((map[int]int)(nil), m1, equal[int]) {
    64  		t.Errorf("EqualFunc(nil, %v, equal) = true, want false", m1)
    65  	}
    66  	if !EqualFunc[map[int]int, map[int]int](nil, nil, equal[int]) {
    67  		t.Error("EqualFunc(nil, nil, equal) = false, want true")
    68  	}
    69  	if ms := map[int]int{1: 2}; EqualFunc(m1, ms, equal[int]) {
    70  		t.Errorf("EqualFunc(%v, %v, equal) = true, want false", m1, ms)
    71  	}
    72  
    73  	// Comparing NaN for equality is expected to fail.
    74  	mf := map[int]float64{1: 0, 2: math.NaN()}
    75  	if EqualFunc(mf, mf, equal[float64]) {
    76  		t.Errorf("EqualFunc(%v, %v, equal) = true, want false", mf, mf)
    77  	}
    78  	// But it should succeed using equalNaN.
    79  	if !EqualFunc(mf, mf, equalNaN[float64]) {
    80  		t.Errorf("EqualFunc(%v, %v, equalNaN) = false, want true", mf, mf)
    81  	}
    82  
    83  	if !EqualFunc(m1, m2, equalIntStr) {
    84  		t.Errorf("EqualFunc(%v, %v, equalIntStr) = false, want true", m1, m2)
    85  	}
    86  }
    87  
    88  func TestClone(t *testing.T) {
    89  	mc := Clone(m1)
    90  	if !Equal(mc, m1) {
    91  		t.Errorf("Clone(%v) = %v, want %v", m1, mc, m1)
    92  	}
    93  	mc[16] = 32
    94  	if Equal(mc, m1) {
    95  		t.Errorf("Equal(%v, %v) = true, want false", mc, m1)
    96  	}
    97  }
    98  
    99  func TestCloneNil(t *testing.T) {
   100  	var m1 map[string]int
   101  	mc := Clone(m1)
   102  	if mc != nil {
   103  		t.Errorf("Clone(%v) = %v, want %v", m1, mc, m1)
   104  	}
   105  }
   106  
   107  func TestCopy(t *testing.T) {
   108  	mc := Clone(m1)
   109  	Copy(mc, mc)
   110  	if !Equal(mc, m1) {
   111  		t.Errorf("Copy(%v, %v) = %v, want %v", m1, m1, mc, m1)
   112  	}
   113  	Copy(mc, map[int]int{16: 32})
   114  	want := map[int]int{1: 2, 2: 4, 4: 8, 8: 16, 16: 32}
   115  	if !Equal(mc, want) {
   116  		t.Errorf("Copy result = %v, want %v", mc, want)
   117  	}
   118  
   119  	type M1 map[int]bool
   120  	type M2 map[int]bool
   121  	Copy(make(M1), make(M2))
   122  }
   123  
   124  func TestDeleteFunc(t *testing.T) {
   125  	mc := Clone(m1)
   126  	DeleteFunc(mc, func(int, int) bool { return false })
   127  	if !Equal(mc, m1) {
   128  		t.Errorf("DeleteFunc(%v, true) = %v, want %v", m1, mc, m1)
   129  	}
   130  	DeleteFunc(mc, func(k, v int) bool { return k > 3 })
   131  	want := map[int]int{1: 2, 2: 4}
   132  	if !Equal(mc, want) {
   133  		t.Errorf("DeleteFunc result = %v, want %v", mc, want)
   134  	}
   135  }
   136  
   137  var n map[int]int
   138  
   139  func BenchmarkMapClone(b *testing.B) {
   140  	var m = make(map[int]int)
   141  	for i := 0; i < 1000000; i++ {
   142  		m[i] = i
   143  	}
   144  	b.ResetTimer()
   145  	for i := 0; i < b.N; i++ {
   146  		n = Clone(m)
   147  	}
   148  }
   149  
   150  func TestCloneWithDelete(t *testing.T) {
   151  	var m = make(map[int]int)
   152  	for i := 0; i < 32; i++ {
   153  		m[i] = i
   154  	}
   155  	for i := 8; i < 32; i++ {
   156  		delete(m, i)
   157  	}
   158  	m2 := Clone(m)
   159  	if len(m2) != 8 {
   160  		t.Errorf("len2(m2) = %d, want %d", len(m2), 8)
   161  	}
   162  	for i := 0; i < 8; i++ {
   163  		if m2[i] != m[i] {
   164  			t.Errorf("m2[%d] = %d, want %d", i, m2[i], m[i])
   165  		}
   166  	}
   167  }
   168  
   169  func TestCloneWithMapAssign(t *testing.T) {
   170  	var m = make(map[int]int)
   171  	const N = 25
   172  	for i := 0; i < N; i++ {
   173  		m[i] = i
   174  	}
   175  	m2 := Clone(m)
   176  	if len(m2) != N {
   177  		t.Errorf("len2(m2) = %d, want %d", len(m2), N)
   178  	}
   179  	for i := 0; i < N; i++ {
   180  		if m2[i] != m[i] {
   181  			t.Errorf("m2[%d] = %d, want %d", i, m2[i], m[i])
   182  		}
   183  	}
   184  }
   185  
   186  func TestCloneLarge(t *testing.T) {
   187  	// See issue 64474.
   188  	type K [17]float64 // > 128 bytes
   189  	type V [17]float64
   190  
   191  	var zero float64
   192  	negZero := -zero
   193  
   194  	for tst := 0; tst < 3; tst++ {
   195  		// Initialize m with a key and value.
   196  		m := map[K]V{}
   197  		var k1 K
   198  		var v1 V
   199  		m[k1] = v1
   200  
   201  		switch tst {
   202  		case 0: // nothing, just a 1-entry map
   203  		case 1:
   204  			// Add more entries to make it 2 buckets
   205  			// 1 entry already
   206  			// 7 more fill up 1 bucket
   207  			// 1 more to grow to 2 buckets
   208  			for i := 0; i < 7+1; i++ {
   209  				m[K{float64(i) + 1}] = V{}
   210  			}
   211  		case 2:
   212  			// Capture the map mid-grow
   213  			// 1 entry already
   214  			// 7 more fill up 1 bucket
   215  			// 5 more (13 total) fill up 2 buckets
   216  			// 13 more (26 total) fill up 4 buckets
   217  			// 1 more to start the 4->8 bucket grow
   218  			for i := 0; i < 7+5+13+1; i++ {
   219  				m[K{float64(i) + 1}] = V{}
   220  			}
   221  		}
   222  
   223  		// Clone m, which should freeze the map's contents.
   224  		c := Clone(m)
   225  
   226  		// Update m with new key and value.
   227  		k2, v2 := k1, v1
   228  		k2[0] = negZero
   229  		v2[0] = 1.0
   230  		m[k2] = v2
   231  
   232  		// Make sure c still has its old key and value.
   233  		for k, v := range c {
   234  			if math.Signbit(k[0]) {
   235  				t.Errorf("tst%d: sign bit of key changed; got %v want %v", tst, k, k1)
   236  			}
   237  			if v != v1 {
   238  				t.Errorf("tst%d: value changed; got %v want %v", tst, v, v1)
   239  			}
   240  		}
   241  	}
   242  }
   243  

View as plain text