github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/runtime/string_test.go (about) 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 "strconv" 10 "strings" 11 "testing" 12 "unicode/utf8" 13 ) 14 15 // Strings and slices that don't escape and fit into tmpBuf are stack allocated, 16 // which defeats using AllocsPerRun to test other optimizations. 17 const sizeNoStack = 100 18 19 func BenchmarkCompareStringEqual(b *testing.B) { 20 bytes := []byte("Hello Gophers!") 21 s1, s2 := string(bytes), string(bytes) 22 for i := 0; i < b.N; i++ { 23 if s1 != s2 { 24 b.Fatal("s1 != s2") 25 } 26 } 27 } 28 29 func BenchmarkCompareStringIdentical(b *testing.B) { 30 s1 := "Hello Gophers!" 31 s2 := s1 32 for i := 0; i < b.N; i++ { 33 if s1 != s2 { 34 b.Fatal("s1 != s2") 35 } 36 } 37 } 38 39 func BenchmarkCompareStringSameLength(b *testing.B) { 40 s1 := "Hello Gophers!" 41 s2 := "Hello, Gophers" 42 for i := 0; i < b.N; i++ { 43 if s1 == s2 { 44 b.Fatal("s1 == s2") 45 } 46 } 47 } 48 49 func BenchmarkCompareStringDifferentLength(b *testing.B) { 50 s1 := "Hello Gophers!" 51 s2 := "Hello, Gophers!" 52 for i := 0; i < b.N; i++ { 53 if s1 == s2 { 54 b.Fatal("s1 == s2") 55 } 56 } 57 } 58 59 func BenchmarkCompareStringBigUnaligned(b *testing.B) { 60 bytes := make([]byte, 0, 1<<20) 61 for len(bytes) < 1<<20 { 62 bytes = append(bytes, "Hello Gophers!"...) 63 } 64 s1, s2 := string(bytes), "hello"+string(bytes) 65 for i := 0; i < b.N; i++ { 66 if s1 != s2[len("hello"):] { 67 b.Fatal("s1 != s2") 68 } 69 } 70 b.SetBytes(int64(len(s1))) 71 } 72 73 func BenchmarkCompareStringBig(b *testing.B) { 74 bytes := make([]byte, 0, 1<<20) 75 for len(bytes) < 1<<20 { 76 bytes = append(bytes, "Hello Gophers!"...) 77 } 78 s1, s2 := string(bytes), string(bytes) 79 for i := 0; i < b.N; i++ { 80 if s1 != s2 { 81 b.Fatal("s1 != s2") 82 } 83 } 84 b.SetBytes(int64(len(s1))) 85 } 86 87 func BenchmarkConcatStringAndBytes(b *testing.B) { 88 s1 := []byte("Gophers!") 89 for i := 0; i < b.N; i++ { 90 _ = "Hello " + string(s1) 91 } 92 } 93 94 var escapeString string 95 96 func BenchmarkSliceByteToString(b *testing.B) { 97 buf := []byte{'!'} 98 for n := 0; n < 8; n++ { 99 b.Run(strconv.Itoa(len(buf)), func(b *testing.B) { 100 for i := 0; i < b.N; i++ { 101 escapeString = string(buf) 102 } 103 }) 104 buf = append(buf, buf...) 105 } 106 } 107 108 var stringdata = []struct{ name, data string }{ 109 {"ASCII", "01234567890"}, 110 {"Japanese", "日本語日本語日本語"}, 111 {"MixedLength", "$Ѐࠀက퀀𐀀\U00040000\U0010FFFF"}, 112 } 113 114 var sinkInt int 115 116 func BenchmarkRuneCount(b *testing.B) { 117 // Each sub-benchmark counts the runes in a string in a different way. 118 b.Run("lenruneslice", func(b *testing.B) { 119 for _, sd := range stringdata { 120 b.Run(sd.name, func(b *testing.B) { 121 for i := 0; i < b.N; i++ { 122 sinkInt += len([]rune(sd.data)) 123 } 124 }) 125 } 126 }) 127 b.Run("rangeloop", func(b *testing.B) { 128 for _, sd := range stringdata { 129 b.Run(sd.name, func(b *testing.B) { 130 for i := 0; i < b.N; i++ { 131 n := 0 132 for range sd.data { 133 n++ 134 } 135 sinkInt += n 136 } 137 }) 138 } 139 }) 140 b.Run("utf8.RuneCountInString", func(b *testing.B) { 141 for _, sd := range stringdata { 142 b.Run(sd.name, func(b *testing.B) { 143 for i := 0; i < b.N; i++ { 144 sinkInt += utf8.RuneCountInString(sd.data) 145 } 146 }) 147 } 148 }) 149 } 150 151 func BenchmarkRuneIterate(b *testing.B) { 152 b.Run("range", func(b *testing.B) { 153 for _, sd := range stringdata { 154 b.Run(sd.name, func(b *testing.B) { 155 for i := 0; i < b.N; i++ { 156 for range sd.data { 157 } 158 } 159 }) 160 } 161 }) 162 b.Run("range1", func(b *testing.B) { 163 for _, sd := range stringdata { 164 b.Run(sd.name, func(b *testing.B) { 165 for i := 0; i < b.N; i++ { 166 for range sd.data { 167 } 168 } 169 }) 170 } 171 }) 172 b.Run("range2", func(b *testing.B) { 173 for _, sd := range stringdata { 174 b.Run(sd.name, func(b *testing.B) { 175 for i := 0; i < b.N; i++ { 176 for range sd.data { 177 } 178 } 179 }) 180 } 181 }) 182 } 183 184 func BenchmarkArrayEqual(b *testing.B) { 185 a1 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} 186 a2 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} 187 b.ResetTimer() 188 for i := 0; i < b.N; i++ { 189 if a1 != a2 { 190 b.Fatal("not equal") 191 } 192 } 193 } 194 195 func TestStringW(t *testing.T) { 196 strings := []string{ 197 "hello", 198 "a\u5566\u7788b", 199 } 200 201 for _, s := range strings { 202 var b []uint16 203 for _, c := range s { 204 b = append(b, uint16(c)) 205 if c != rune(uint16(c)) { 206 t.Errorf("bad test: stringW can't handle >16 bit runes") 207 } 208 } 209 b = append(b, 0) 210 r := runtime.GostringW(b) 211 if r != s { 212 t.Errorf("gostringW(%v) = %s, want %s", b, r, s) 213 } 214 } 215 } 216 217 func TestLargeStringConcat(t *testing.T) { 218 output := runTestProg(t, "testprog", "stringconcat") 219 want := "panic: " + strings.Repeat("0", 1<<10) + strings.Repeat("1", 1<<10) + 220 strings.Repeat("2", 1<<10) + strings.Repeat("3", 1<<10) 221 if !strings.HasPrefix(output, want) { 222 t.Fatalf("output does not start with %q:\n%s", want, output) 223 } 224 } 225 226 func TestCompareTempString(t *testing.T) { 227 s := strings.Repeat("x", sizeNoStack) 228 b := []byte(s) 229 n := testing.AllocsPerRun(1000, func() { 230 if string(b) != s { 231 t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) 232 } 233 if string(b) == s { 234 } else { 235 t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) 236 } 237 }) 238 if n != 0 { 239 t.Fatalf("want 0 allocs, got %v", n) 240 } 241 } 242 243 func TestStringOnStack(t *testing.T) { 244 s := "" 245 for i := 0; i < 3; i++ { 246 s = "a" + s + "b" + s + "c" 247 } 248 249 if want := "aaabcbabccbaabcbabccc"; s != want { 250 t.Fatalf("want: '%v', got '%v'", want, s) 251 } 252 } 253 254 func TestIntString(t *testing.T) { 255 // Non-escaping result of intstring. 256 s := "" 257 for i := 0; i < 4; i++ { 258 s += string(i+'0') + string(i+'0'+1) 259 } 260 if want := "01122334"; s != want { 261 t.Fatalf("want '%v', got '%v'", want, s) 262 } 263 264 // Escaping result of intstring. 265 var a [4]string 266 for i := 0; i < 4; i++ { 267 a[i] = string(i + '0') 268 } 269 s = a[0] + a[1] + a[2] + a[3] 270 if want := "0123"; s != want { 271 t.Fatalf("want '%v', got '%v'", want, s) 272 } 273 } 274 275 func TestIntStringAllocs(t *testing.T) { 276 unknown := '0' 277 n := testing.AllocsPerRun(1000, func() { 278 s1 := string(unknown) 279 s2 := string(unknown + 1) 280 if s1 == s2 { 281 t.Fatalf("bad") 282 } 283 }) 284 if n != 0 { 285 t.Fatalf("want 0 allocs, got %v", n) 286 } 287 } 288 289 func TestRangeStringCast(t *testing.T) { 290 s := strings.Repeat("x", sizeNoStack) 291 n := testing.AllocsPerRun(1000, func() { 292 for i, c := range []byte(s) { 293 if c != s[i] { 294 t.Fatalf("want '%c' at pos %v, got '%c'", s[i], i, c) 295 } 296 } 297 }) 298 if n != 0 { 299 t.Fatalf("want 0 allocs, got %v", n) 300 } 301 } 302 303 func isZeroed(b []byte) bool { 304 for _, x := range b { 305 if x != 0 { 306 return false 307 } 308 } 309 return true 310 } 311 312 func isZeroedR(r []rune) bool { 313 for _, x := range r { 314 if x != 0 { 315 return false 316 } 317 } 318 return true 319 } 320 321 func TestString2Slice(t *testing.T) { 322 // Make sure we don't return slices that expose 323 // an unzeroed section of stack-allocated temp buf 324 // between len and cap. See issue 14232. 325 s := "foož" 326 b := ([]byte)(s) 327 if !isZeroed(b[len(b):cap(b)]) { 328 t.Errorf("extra bytes not zeroed") 329 } 330 r := ([]rune)(s) 331 if !isZeroedR(r[len(r):cap(r)]) { 332 t.Errorf("extra runes not zeroed") 333 } 334 } 335 336 const intSize = 32 << (^uint(0) >> 63) 337 338 type atoi64Test struct { 339 in string 340 out int64 341 ok bool 342 } 343 344 var atoi64tests = []atoi64Test{ 345 {"", 0, false}, 346 {"0", 0, true}, 347 {"-0", 0, true}, 348 {"1", 1, true}, 349 {"-1", -1, true}, 350 {"12345", 12345, true}, 351 {"-12345", -12345, true}, 352 {"012345", 12345, true}, 353 {"-012345", -12345, true}, 354 {"12345x", 0, false}, 355 {"-12345x", 0, false}, 356 {"98765432100", 98765432100, true}, 357 {"-98765432100", -98765432100, true}, 358 {"20496382327982653440", 0, false}, 359 {"-20496382327982653440", 0, false}, 360 {"9223372036854775807", 1<<63 - 1, true}, 361 {"-9223372036854775807", -(1<<63 - 1), true}, 362 {"9223372036854775808", 0, false}, 363 {"-9223372036854775808", -1 << 63, true}, 364 {"9223372036854775809", 0, false}, 365 {"-9223372036854775809", 0, false}, 366 } 367 368 func TestAtoi(t *testing.T) { 369 switch intSize { 370 case 32: 371 for i := range atoi32tests { 372 test := &atoi32tests[i] 373 out, ok := runtime.Atoi(test.in) 374 if test.out != int32(out) || test.ok != ok { 375 t.Errorf("atoi(%q) = (%v, %v) want (%v, %v)", 376 test.in, out, ok, test.out, test.ok) 377 } 378 } 379 case 64: 380 for i := range atoi64tests { 381 test := &atoi64tests[i] 382 out, ok := runtime.Atoi(test.in) 383 if test.out != int64(out) || test.ok != ok { 384 t.Errorf("atoi(%q) = (%v, %v) want (%v, %v)", 385 test.in, out, ok, test.out, test.ok) 386 } 387 } 388 } 389 } 390 391 type atoi32Test struct { 392 in string 393 out int32 394 ok bool 395 } 396 397 var atoi32tests = []atoi32Test{ 398 {"", 0, false}, 399 {"0", 0, true}, 400 {"-0", 0, true}, 401 {"1", 1, true}, 402 {"-1", -1, true}, 403 {"12345", 12345, true}, 404 {"-12345", -12345, true}, 405 {"012345", 12345, true}, 406 {"-012345", -12345, true}, 407 {"12345x", 0, false}, 408 {"-12345x", 0, false}, 409 {"987654321", 987654321, true}, 410 {"-987654321", -987654321, true}, 411 {"2147483647", 1<<31 - 1, true}, 412 {"-2147483647", -(1<<31 - 1), true}, 413 {"2147483648", 0, false}, 414 {"-2147483648", -1 << 31, true}, 415 {"2147483649", 0, false}, 416 {"-2147483649", 0, false}, 417 } 418 419 func TestAtoi32(t *testing.T) { 420 for i := range atoi32tests { 421 test := &atoi32tests[i] 422 out, ok := runtime.Atoi32(test.in) 423 if test.out != out || test.ok != ok { 424 t.Errorf("atoi32(%q) = (%v, %v) want (%v, %v)", 425 test.in, out, ok, test.out, test.ok) 426 } 427 } 428 }