Source file src/internal/intern/intern_test.go

     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  }
   198  

View as plain text