github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/internal/intern/intern_test.go (about) 1 // Copyright 2020 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 intern 6 7 import ( 8 "fmt" 9 "runtime" 10 "testing" 11 ) 12 13 func TestBasics(t *testing.T) { 14 clearMap() 15 foo := Get("foo") 16 bar := Get("bar") 17 empty := Get("") 18 nilEface := Get(nil) 19 i := Get(0x7777777) 20 foo2 := Get("foo") 21 bar2 := Get("bar") 22 empty2 := Get("") 23 nilEface2 := Get(nil) 24 i2 := Get(0x7777777) 25 foo3 := GetByString("foo") 26 empty3 := GetByString("") 27 28 if foo.Get() != foo2.Get() { 29 t.Error("foo/foo2 values differ") 30 } 31 if foo.Get() != foo3.Get() { 32 t.Error("foo/foo3 values differ") 33 } 34 if foo.Get() != "foo" { 35 t.Error("foo.Get not foo") 36 } 37 if foo != foo2 { 38 t.Error("foo/foo2 pointers differ") 39 } 40 if foo != foo3 { 41 t.Error("foo/foo3 pointers differ") 42 } 43 44 if bar.Get() != bar2.Get() { 45 t.Error("bar values differ") 46 } 47 if bar.Get() != "bar" { 48 t.Error("bar.Get not bar") 49 } 50 if bar != bar2 { 51 t.Error("bar pointers differ") 52 } 53 54 if i.Get() != i.Get() { 55 t.Error("i values differ") 56 } 57 if i.Get() != 0x7777777 { 58 t.Error("i.Get not 0x7777777") 59 } 60 if i != i2 { 61 t.Error("i pointers differ") 62 } 63 64 if empty.Get() != empty2.Get() { 65 t.Error("empty/empty2 values differ") 66 } 67 if empty.Get() != empty.Get() { 68 t.Error("empty/empty3 values differ") 69 } 70 if empty.Get() != "" { 71 t.Error("empty.Get not empty string") 72 } 73 if empty != empty2 { 74 t.Error("empty/empty2 pointers differ") 75 } 76 if empty != empty3 { 77 t.Error("empty/empty3 pointers differ") 78 } 79 80 if nilEface.Get() != nilEface2.Get() { 81 t.Error("nilEface values differ") 82 } 83 if nilEface.Get() != nil { 84 t.Error("nilEface.Get not nil") 85 } 86 if nilEface != nilEface2 { 87 t.Error("nilEface pointers differ") 88 } 89 90 if n := mapLen(); n != 5 { 91 t.Errorf("map len = %d; want 4", n) 92 } 93 94 wantEmpty(t) 95 } 96 97 func wantEmpty(t testing.TB) { 98 t.Helper() 99 const gcTries = 5000 100 for try := 0; try < gcTries; try++ { 101 runtime.GC() 102 n := mapLen() 103 if n == 0 { 104 break 105 } 106 if try == gcTries-1 { 107 t.Errorf("map len = %d after (%d GC tries); want 0, contents: %v", n, gcTries, mapKeys()) 108 } 109 } 110 } 111 112 func TestStress(t *testing.T) { 113 iters := 10000 114 if testing.Short() { 115 iters = 1000 116 } 117 var sink []byte 118 for i := 0; i < iters; i++ { 119 _ = Get("foo") 120 sink = make([]byte, 1<<20) 121 } 122 _ = sink 123 } 124 125 func BenchmarkStress(b *testing.B) { 126 done := make(chan struct{}) 127 defer close(done) 128 go func() { 129 for { 130 select { 131 case <-done: 132 return 133 default: 134 } 135 runtime.GC() 136 } 137 }() 138 139 clearMap() 140 v1 := Get("foo") 141 b.ReportAllocs() 142 b.RunParallel(func(pb *testing.PB) { 143 for pb.Next() { 144 v2 := Get("foo") 145 if v1 != v2 { 146 b.Fatal("wrong value") 147 } 148 // And also a key we don't retain: 149 _ = Get("bar") 150 } 151 }) 152 runtime.GC() 153 wantEmpty(b) 154 } 155 156 func mapLen() int { 157 mu.Lock() 158 defer mu.Unlock() 159 return len(valMap) 160 } 161 162 func mapKeys() (keys []string) { 163 mu.Lock() 164 defer mu.Unlock() 165 for k := range valMap { 166 keys = append(keys, fmt.Sprint(k)) 167 } 168 return keys 169 } 170 171 func clearMap() { 172 mu.Lock() 173 defer mu.Unlock() 174 clear(valMap) 175 } 176 177 var ( 178 globalString = "not a constant" 179 sink string 180 ) 181 182 func TestGetByStringAllocs(t *testing.T) { 183 allocs := int(testing.AllocsPerRun(100, func() { 184 GetByString(globalString) 185 })) 186 if allocs != 0 { 187 t.Errorf("GetString allocated %d objects, want 0", allocs) 188 } 189 } 190 191 func BenchmarkGetByString(b *testing.B) { 192 b.ReportAllocs() 193 for i := 0; i < b.N; i++ { 194 v := GetByString(globalString) 195 sink = v.Get().(string) 196 } 197 }