2017-03-02 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libgo / go / runtime / string_test.go
blobee306999e2e2920984512a2ebb641d2c4be7f10a
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.
5 package runtime_test
7 import (
8 "runtime"
9 "strings"
10 "testing"
13 // Strings and slices that don't escape and fit into tmpBuf are stack allocated,
14 // which defeats using AllocsPerRun to test other optimizations.
15 const sizeNoStack = 100
17 func BenchmarkCompareStringEqual(b *testing.B) {
18 bytes := []byte("Hello Gophers!")
19 s1, s2 := string(bytes), string(bytes)
20 for i := 0; i < b.N; i++ {
21 if s1 != s2 {
22 b.Fatal("s1 != s2")
27 func BenchmarkCompareStringIdentical(b *testing.B) {
28 s1 := "Hello Gophers!"
29 s2 := s1
30 for i := 0; i < b.N; i++ {
31 if s1 != s2 {
32 b.Fatal("s1 != s2")
37 func BenchmarkCompareStringSameLength(b *testing.B) {
38 s1 := "Hello Gophers!"
39 s2 := "Hello, Gophers"
40 for i := 0; i < b.N; i++ {
41 if s1 == s2 {
42 b.Fatal("s1 == s2")
47 func BenchmarkCompareStringDifferentLength(b *testing.B) {
48 s1 := "Hello Gophers!"
49 s2 := "Hello, Gophers!"
50 for i := 0; i < b.N; i++ {
51 if s1 == s2 {
52 b.Fatal("s1 == s2")
57 func BenchmarkCompareStringBigUnaligned(b *testing.B) {
58 bytes := make([]byte, 0, 1<<20)
59 for len(bytes) < 1<<20 {
60 bytes = append(bytes, "Hello Gophers!"...)
62 s1, s2 := string(bytes), "hello"+string(bytes)
63 for i := 0; i < b.N; i++ {
64 if s1 != s2[len("hello"):] {
65 b.Fatal("s1 != s2")
68 b.SetBytes(int64(len(s1)))
71 func BenchmarkCompareStringBig(b *testing.B) {
72 bytes := make([]byte, 0, 1<<20)
73 for len(bytes) < 1<<20 {
74 bytes = append(bytes, "Hello Gophers!"...)
76 s1, s2 := string(bytes), string(bytes)
77 for i := 0; i < b.N; i++ {
78 if s1 != s2 {
79 b.Fatal("s1 != s2")
82 b.SetBytes(int64(len(s1)))
85 func BenchmarkConcatStringAndBytes(b *testing.B) {
86 s1 := []byte("Gophers!")
87 for i := 0; i < b.N; i++ {
88 _ = "Hello " + string(s1)
92 var stringdata = []struct{ name, data string }{
93 {"ASCII", "01234567890"},
94 {"Japanese", "日本語日本語日本語"},
95 {"MixedLength", "$Ѐࠀက퀀𐀀\U00040000\U0010FFFF"},
98 func BenchmarkRuneIterate(b *testing.B) {
99 b.Run("range", func(b *testing.B) {
100 for _, sd := range stringdata {
101 b.Run(sd.name, func(b *testing.B) {
102 for i := 0; i < b.N; i++ {
103 for range sd.data {
109 b.Run("range1", func(b *testing.B) {
110 for _, sd := range stringdata {
111 b.Run(sd.name, func(b *testing.B) {
112 for i := 0; i < b.N; i++ {
113 for _ = range sd.data {
119 b.Run("range2", func(b *testing.B) {
120 for _, sd := range stringdata {
121 b.Run(sd.name, func(b *testing.B) {
122 for i := 0; i < b.N; i++ {
123 for _, _ = range sd.data {
131 func BenchmarkArrayEqual(b *testing.B) {
132 a1 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
133 a2 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
134 b.ResetTimer()
135 for i := 0; i < b.N; i++ {
136 if a1 != a2 {
137 b.Fatal("not equal")
143 func TestStringW(t *testing.T) {
144 strings := []string{
145 "hello",
146 "a\u5566\u7788b",
149 for _, s := range strings {
150 var b []uint16
151 for _, c := range s {
152 b = append(b, uint16(c))
153 if c != rune(uint16(c)) {
154 t.Errorf("bad test: stringW can't handle >16 bit runes")
157 b = append(b, 0)
158 r := runtime.GostringW(b)
159 if r != s {
160 t.Errorf("gostringW(%v) = %s, want %s", b, r, s)
166 func TestLargeStringConcat(t *testing.T) {
167 output := runTestProg(t, "testprog", "stringconcat")
168 want := "panic: " + strings.Repeat("0", 1<<10) + strings.Repeat("1", 1<<10) +
169 strings.Repeat("2", 1<<10) + strings.Repeat("3", 1<<10)
170 if !strings.HasPrefix(output, want) {
171 t.Fatalf("output does not start with %q:\n%s", want, output)
175 func TestCompareTempString(t *testing.T) {
176 s := strings.Repeat("x", sizeNoStack)
177 b := []byte(s)
178 n := testing.AllocsPerRun(1000, func() {
179 if string(b) != s {
180 t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
182 if string(b) == s {
183 } else {
184 t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
187 // was n != 0, changed for gccgo.
188 if n > 2 {
189 t.Fatalf("want 0 allocs, got %v", n)
193 func TestStringOnStack(t *testing.T) {
194 s := ""
195 for i := 0; i < 3; i++ {
196 s = "a" + s + "b" + s + "c"
199 if want := "aaabcbabccbaabcbabccc"; s != want {
200 t.Fatalf("want: '%v', got '%v'", want, s)
204 func TestIntString(t *testing.T) {
205 // Non-escaping result of intstring.
206 s := ""
207 for i := 0; i < 4; i++ {
208 s += string(i+'0') + string(i+'0'+1)
210 if want := "01122334"; s != want {
211 t.Fatalf("want '%v', got '%v'", want, s)
214 // Escaping result of intstring.
215 var a [4]string
216 for i := 0; i < 4; i++ {
217 a[i] = string(i + '0')
219 s = a[0] + a[1] + a[2] + a[3]
220 if want := "0123"; s != want {
221 t.Fatalf("want '%v', got '%v'", want, s)
225 func TestIntStringAllocs(t *testing.T) {
226 unknown := '0'
227 n := testing.AllocsPerRun(1000, func() {
228 s1 := string(unknown)
229 s2 := string(unknown + 1)
230 if s1 == s2 {
231 t.Fatalf("bad")
234 // was n != 0, changed for gccgo, which currently does one
235 // allocation for each call to string(unknown).
236 if n > 2 {
237 t.Fatalf("want 0 allocs, got %v", n)
241 func TestRangeStringCast(t *testing.T) {
242 s := strings.Repeat("x", sizeNoStack)
243 n := testing.AllocsPerRun(1000, func() {
244 for i, c := range []byte(s) {
245 if c != s[i] {
246 t.Fatalf("want '%c' at pos %v, got '%c'", s[i], i, c)
250 // was n != 0, changed for gccgo.
251 if n > 1 {
252 t.Fatalf("want 0 allocs, got %v", n)
256 func isZeroed(b []byte) bool {
257 for _, x := range b {
258 if x != 0 {
259 return false
262 return true
265 func isZeroedR(r []rune) bool {
266 for _, x := range r {
267 if x != 0 {
268 return false
271 return true
274 func TestString2Slice(t *testing.T) {
275 // Make sure we don't return slices that expose
276 // an unzeroed section of stack-allocated temp buf
277 // between len and cap. See issue 14232.
278 s := "foož"
279 b := ([]byte)(s)
280 if !isZeroed(b[len(b):cap(b)]) {
281 t.Errorf("extra bytes not zeroed")
283 r := ([]rune)(s)
284 if !isZeroedR(r[len(r):cap(r)]) {
285 t.Errorf("extra runes not zeroed")
289 const intSize = 32 << (^uint(0) >> 63)
291 type atoi64Test struct {
292 in string
293 out int64
294 ok bool
297 var atoi64tests = []atoi64Test{
298 {"", 0, false},
299 {"0", 0, true},
300 {"-0", 0, true},
301 {"1", 1, true},
302 {"-1", -1, true},
303 {"12345", 12345, true},
304 {"-12345", -12345, true},
305 {"012345", 12345, true},
306 {"-012345", -12345, true},
307 {"12345x", 0, false},
308 {"-12345x", 0, false},
309 {"98765432100", 98765432100, true},
310 {"-98765432100", -98765432100, true},
311 {"20496382327982653440", 0, false},
312 {"-20496382327982653440", 0, false},
313 {"9223372036854775807", 1<<63 - 1, true},
314 {"-9223372036854775807", -(1<<63 - 1), true},
315 {"9223372036854775808", 0, false},
316 {"-9223372036854775808", -1 << 63, true},
317 {"9223372036854775809", 0, false},
318 {"-9223372036854775809", 0, false},
321 func TestAtoi(t *testing.T) {
322 switch intSize {
323 case 32:
324 for i := range atoi32tests {
325 test := &atoi32tests[i]
326 out, ok := runtime.Atoi(test.in)
327 if test.out != int32(out) || test.ok != ok {
328 t.Errorf("atoi(%q) = (%v, %v) want (%v, %v)",
329 test.in, out, ok, test.out, test.ok)
332 case 64:
333 for i := range atoi64tests {
334 test := &atoi64tests[i]
335 out, ok := runtime.Atoi(test.in)
336 if test.out != int64(out) || test.ok != ok {
337 t.Errorf("atoi(%q) = (%v, %v) want (%v, %v)",
338 test.in, out, ok, test.out, test.ok)
344 type atoi32Test struct {
345 in string
346 out int32
347 ok bool
350 var atoi32tests = []atoi32Test{
351 {"", 0, false},
352 {"0", 0, true},
353 {"-0", 0, true},
354 {"1", 1, true},
355 {"-1", -1, true},
356 {"12345", 12345, true},
357 {"-12345", -12345, true},
358 {"012345", 12345, true},
359 {"-012345", -12345, true},
360 {"12345x", 0, false},
361 {"-12345x", 0, false},
362 {"987654321", 987654321, true},
363 {"-987654321", -987654321, true},
364 {"2147483647", 1<<31 - 1, true},
365 {"-2147483647", -(1<<31 - 1), true},
366 {"2147483648", 0, false},
367 {"-2147483648", -1 << 31, true},
368 {"2147483649", 0, false},
369 {"-2147483649", 0, false},
372 func TestAtoi32(t *testing.T) {
373 for i := range atoi32tests {
374 test := &atoi32tests[i]
375 out, ok := runtime.Atoi32(test.in)
376 if test.out != out || test.ok != ok {
377 t.Errorf("atoi32(%q) = (%v, %v) want (%v, %v)",
378 test.in, out, ok, test.out, test.ok)