1 // Copyright 2012 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 runtime_test 6 7 import ( 8 "runtime" 9 "strings" 10 "testing" 11 ) 12 13 func BenchmarkCompareStringEqual(b *testing.B) { 14 bytes := []byte("Hello Gophers!") 15 s1, s2 := string(bytes), string(bytes) 16 for i := 0; i < b.N; i++ { 17 if s1 != s2 { 18 b.Fatal("s1 != s2") 19 } 20 } 21 } 22 23 func BenchmarkCompareStringIdentical(b *testing.B) { 24 s1 := "Hello Gophers!" 25 s2 := s1 26 for i := 0; i < b.N; i++ { 27 if s1 != s2 { 28 b.Fatal("s1 != s2") 29 } 30 } 31 } 32 33 func BenchmarkCompareStringSameLength(b *testing.B) { 34 s1 := "Hello Gophers!" 35 s2 := "Hello, Gophers" 36 for i := 0; i < b.N; i++ { 37 if s1 == s2 { 38 b.Fatal("s1 == s2") 39 } 40 } 41 } 42 43 func BenchmarkCompareStringDifferentLength(b *testing.B) { 44 s1 := "Hello Gophers!" 45 s2 := "Hello, Gophers!" 46 for i := 0; i < b.N; i++ { 47 if s1 == s2 { 48 b.Fatal("s1 == s2") 49 } 50 } 51 } 52 53 func BenchmarkCompareStringBigUnaligned(b *testing.B) { 54 bytes := make([]byte, 0, 1<<20) 55 for len(bytes) < 1<<20 { 56 bytes = append(bytes, "Hello Gophers!"...) 57 } 58 s1, s2 := string(bytes), "hello"+string(bytes) 59 for i := 0; i < b.N; i++ { 60 if s1 != s2[len("hello"):] { 61 b.Fatal("s1 != s2") 62 } 63 } 64 b.SetBytes(int64(len(s1))) 65 } 66 67 func BenchmarkCompareStringBig(b *testing.B) { 68 bytes := make([]byte, 0, 1<<20) 69 for len(bytes) < 1<<20 { 70 bytes = append(bytes, "Hello Gophers!"...) 71 } 72 s1, s2 := string(bytes), string(bytes) 73 for i := 0; i < b.N; i++ { 74 if s1 != s2 { 75 b.Fatal("s1 != s2") 76 } 77 } 78 b.SetBytes(int64(len(s1))) 79 } 80 81 func BenchmarkRuneIterate(b *testing.B) { 82 bytes := make([]byte, 100) 83 for i := range bytes { 84 bytes[i] = byte('A') 85 } 86 s := string(bytes) 87 for i := 0; i < b.N; i++ { 88 for range s { 89 } 90 } 91 } 92 93 func BenchmarkRuneIterate2(b *testing.B) { 94 bytes := make([]byte, 100) 95 for i := range bytes { 96 bytes[i] = byte('A') 97 } 98 s := string(bytes) 99 for i := 0; i < b.N; i++ { 100 for range s { 101 } 102 } 103 } 104 105 func TestStringW(t *testing.T) { 106 strings := []string{ 107 "hello", 108 "a\u5566\u7788b", 109 } 110 111 for _, s := range strings { 112 var b []uint16 113 for _, c := range s { 114 b = append(b, uint16(c)) 115 if c != rune(uint16(c)) { 116 t.Errorf("bad test: stringW can't handle >16 bit runes") 117 } 118 } 119 b = append(b, 0) 120 r := runtime.GostringW(b) 121 if r != s { 122 t.Errorf("gostringW(%v) = %s, want %s", b, r, s) 123 } 124 } 125 } 126 127 func TestLargeStringConcat(t *testing.T) { 128 output := executeTest(t, largeStringConcatSource, nil) 129 want := "panic: " + strings.Repeat("0", 1<<10) + strings.Repeat("1", 1<<10) + 130 strings.Repeat("2", 1<<10) + strings.Repeat("3", 1<<10) 131 if !strings.HasPrefix(output, want) { 132 t.Fatalf("output does not start with %q:\n%s", want, output) 133 } 134 } 135 136 var largeStringConcatSource = ` 137 package main 138 import "strings" 139 func main() { 140 s0 := strings.Repeat("0", 1<<10) 141 s1 := strings.Repeat("1", 1<<10) 142 s2 := strings.Repeat("2", 1<<10) 143 s3 := strings.Repeat("3", 1<<10) 144 s := s0 + s1 + s2 + s3 145 panic(s) 146 } 147 ` 148 149 func TestGostringnocopy(t *testing.T) { 150 max := *runtime.Maxstring 151 b := make([]byte, max+10) 152 for i := uintptr(0); i < max+9; i++ { 153 b[i] = 'a' 154 } 155 _ = runtime.Gostringnocopy(&b[0]) 156 newmax := *runtime.Maxstring 157 if newmax != max+9 { 158 t.Errorf("want %d, got %d", max+9, newmax) 159 } 160 } 161 162 func TestCompareTempString(t *testing.T) { 163 s := "foo" 164 b := []byte(s) 165 n := testing.AllocsPerRun(1000, func() { 166 if string(b) != s { 167 t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) 168 } 169 if string(b) == s { 170 } else { 171 t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) 172 } 173 }) 174 if n != 0 { 175 t.Fatalf("want 0 allocs, got %v", n) 176 } 177 } 178 179 func TestStringOnStack(t *testing.T) { 180 s := "" 181 for i := 0; i < 3; i++ { 182 s = "a" + s + "b" + s + "c" 183 } 184 185 if want := "aaabcbabccbaabcbabccc"; s != want { 186 t.Fatalf("want: '%v', got '%v'", want, s) 187 } 188 } 189 190 func TestIntString(t *testing.T) { 191 // Non-escaping result of intstring. 192 s := "" 193 for i := 0; i < 4; i++ { 194 s += string(i+'0') + string(i+'0'+1) 195 } 196 if want := "01122334"; s != want { 197 t.Fatalf("want '%v', got '%v'", want, s) 198 } 199 200 // Escaping result of intstring. 201 var a [4]string 202 for i := 0; i < 4; i++ { 203 a[i] = string(i + '0') 204 } 205 s = a[0] + a[1] + a[2] + a[3] 206 if want := "0123"; s != want { 207 t.Fatalf("want '%v', got '%v'", want, s) 208 } 209 } 210 211 func TestIntStringAllocs(t *testing.T) { 212 unknown := '0' 213 n := testing.AllocsPerRun(1000, func() { 214 s1 := string(unknown) 215 s2 := string(unknown + 1) 216 if s1 == s2 { 217 t.Fatalf("bad") 218 } 219 }) 220 if n != 0 { 221 t.Fatalf("want 0 allocs, got %v", n) 222 } 223 } 224 225 func TestRangeStringCast(t *testing.T) { 226 s := "abc" 227 n := testing.AllocsPerRun(1000, func() { 228 for i, c := range []byte(s) { 229 if c != s[i] { 230 t.Fatalf("want '%c' at pos %v, got '%c'", s[i], i, c) 231 } 232 } 233 }) 234 if n != 0 { 235 t.Fatalf("want 0 allocs, got %v", n) 236 } 237 } 238