Add config file so b4 uses inbox.sourceware.org automatically
[official-gcc.git] / libgo / go / strings / builder_test.go
blob61c0cf40d51d484de8044f4664e39291f09e3824
1 // Copyright 2017 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 strings_test
7 import (
8 "bytes"
9 "runtime"
10 . "strings"
11 "testing"
12 "unicode/utf8"
15 func check(t *testing.T, b *Builder, want string) {
16 t.Helper()
17 got := b.String()
18 if got != want {
19 t.Errorf("String: got %#q; want %#q", got, want)
20 return
22 if n := b.Len(); n != len(got) {
23 t.Errorf("Len: got %d; but len(String()) is %d", n, len(got))
25 if n := b.Cap(); n < len(got) {
26 t.Errorf("Cap: got %d; but len(String()) is %d", n, len(got))
30 func TestBuilder(t *testing.T) {
31 var b Builder
32 check(t, &b, "")
33 n, err := b.WriteString("hello")
34 if err != nil || n != 5 {
35 t.Errorf("WriteString: got %d,%s; want 5,nil", n, err)
37 check(t, &b, "hello")
38 if err = b.WriteByte(' '); err != nil {
39 t.Errorf("WriteByte: %s", err)
41 check(t, &b, "hello ")
42 n, err = b.WriteString("world")
43 if err != nil || n != 5 {
44 t.Errorf("WriteString: got %d,%s; want 5,nil", n, err)
46 check(t, &b, "hello world")
49 func TestBuilderString(t *testing.T) {
50 var b Builder
51 b.WriteString("alpha")
52 check(t, &b, "alpha")
53 s1 := b.String()
54 b.WriteString("beta")
55 check(t, &b, "alphabeta")
56 s2 := b.String()
57 b.WriteString("gamma")
58 check(t, &b, "alphabetagamma")
59 s3 := b.String()
61 // Check that subsequent operations didn't change the returned strings.
62 if want := "alpha"; s1 != want {
63 t.Errorf("first String result is now %q; want %q", s1, want)
65 if want := "alphabeta"; s2 != want {
66 t.Errorf("second String result is now %q; want %q", s2, want)
68 if want := "alphabetagamma"; s3 != want {
69 t.Errorf("third String result is now %q; want %q", s3, want)
73 func TestBuilderReset(t *testing.T) {
74 var b Builder
75 check(t, &b, "")
76 b.WriteString("aaa")
77 s := b.String()
78 check(t, &b, "aaa")
79 b.Reset()
80 check(t, &b, "")
82 // Ensure that writing after Reset doesn't alter
83 // previously returned strings.
84 b.WriteString("bbb")
85 check(t, &b, "bbb")
86 if want := "aaa"; s != want {
87 t.Errorf("previous String result changed after Reset: got %q; want %q", s, want)
91 func TestBuilderGrow(t *testing.T) {
92 if runtime.Compiler == "gccgo" {
93 t.Skip("skip for gccgo until escape analysis improves")
95 for _, growLen := range []int{0, 100, 1000, 10000, 100000} {
96 p := bytes.Repeat([]byte{'a'}, growLen)
97 allocs := testing.AllocsPerRun(100, func() {
98 var b Builder
99 b.Grow(growLen) // should be only alloc, when growLen > 0
100 if b.Cap() < growLen {
101 t.Fatalf("growLen=%d: Cap() is lower than growLen", growLen)
103 b.Write(p)
104 if b.String() != string(p) {
105 t.Fatalf("growLen=%d: bad data written after Grow", growLen)
108 wantAllocs := 1
109 if growLen == 0 {
110 wantAllocs = 0
112 if g, w := int(allocs), wantAllocs; g != w {
113 t.Errorf("growLen=%d: got %d allocs during Write; want %v", growLen, g, w)
118 func TestBuilderWrite2(t *testing.T) {
119 const s0 = "hello 世界"
120 for _, tt := range []struct {
121 name string
122 fn func(b *Builder) (int, error)
123 n int
124 want string
127 "Write",
128 func(b *Builder) (int, error) { return b.Write([]byte(s0)) },
129 len(s0),
133 "WriteRune",
134 func(b *Builder) (int, error) { return b.WriteRune('a') },
136 "a",
139 "WriteRuneWide",
140 func(b *Builder) (int, error) { return b.WriteRune('世') },
142 "世",
145 "WriteString",
146 func(b *Builder) (int, error) { return b.WriteString(s0) },
147 len(s0),
151 t.Run(tt.name, func(t *testing.T) {
152 var b Builder
153 n, err := tt.fn(&b)
154 if err != nil {
155 t.Fatalf("first call: got %s", err)
157 if n != tt.n {
158 t.Errorf("first call: got n=%d; want %d", n, tt.n)
160 check(t, &b, tt.want)
162 n, err = tt.fn(&b)
163 if err != nil {
164 t.Fatalf("second call: got %s", err)
166 if n != tt.n {
167 t.Errorf("second call: got n=%d; want %d", n, tt.n)
169 check(t, &b, tt.want+tt.want)
174 func TestBuilderWriteByte(t *testing.T) {
175 var b Builder
176 if err := b.WriteByte('a'); err != nil {
177 t.Error(err)
179 if err := b.WriteByte(0); err != nil {
180 t.Error(err)
182 check(t, &b, "a\x00")
185 func TestBuilderAllocs(t *testing.T) {
186 if runtime.Compiler == "gccgo" {
187 t.Skip("skip for gccgo until escape analysis improves")
189 // Issue 23382; verify that copyCheck doesn't force the
190 // Builder to escape and be heap allocated.
191 n := testing.AllocsPerRun(10000, func() {
192 var b Builder
193 b.Grow(5)
194 b.WriteString("abcde")
195 _ = b.String()
197 if n != 1 {
198 t.Errorf("Builder allocs = %v; want 1", n)
202 func TestBuilderCopyPanic(t *testing.T) {
203 tests := []struct {
204 name string
205 fn func()
206 wantPanic bool
209 name: "String",
210 wantPanic: false,
211 fn: func() {
212 var a Builder
213 a.WriteByte('x')
214 b := a
215 _ = b.String() // appease vet
219 name: "Len",
220 wantPanic: false,
221 fn: func() {
222 var a Builder
223 a.WriteByte('x')
224 b := a
225 b.Len()
229 name: "Cap",
230 wantPanic: false,
231 fn: func() {
232 var a Builder
233 a.WriteByte('x')
234 b := a
235 b.Cap()
239 name: "Reset",
240 wantPanic: false,
241 fn: func() {
242 var a Builder
243 a.WriteByte('x')
244 b := a
245 b.Reset()
246 b.WriteByte('y')
250 name: "Write",
251 wantPanic: true,
252 fn: func() {
253 var a Builder
254 a.Write([]byte("x"))
255 b := a
256 b.Write([]byte("y"))
260 name: "WriteByte",
261 wantPanic: true,
262 fn: func() {
263 var a Builder
264 a.WriteByte('x')
265 b := a
266 b.WriteByte('y')
270 name: "WriteString",
271 wantPanic: true,
272 fn: func() {
273 var a Builder
274 a.WriteString("x")
275 b := a
276 b.WriteString("y")
280 name: "WriteRune",
281 wantPanic: true,
282 fn: func() {
283 var a Builder
284 a.WriteRune('x')
285 b := a
286 b.WriteRune('y')
290 name: "Grow",
291 wantPanic: true,
292 fn: func() {
293 var a Builder
294 a.Grow(1)
295 b := a
296 b.Grow(2)
300 for _, tt := range tests {
301 didPanic := make(chan bool)
302 go func() {
303 defer func() { didPanic <- recover() != nil }()
304 tt.fn()
306 if got := <-didPanic; got != tt.wantPanic {
307 t.Errorf("%s: panicked = %v; want %v", tt.name, got, tt.wantPanic)
312 func TestBuilderWriteInvalidRune(t *testing.T) {
313 // Invalid runes, including negative ones, should be written as
314 // utf8.RuneError.
315 for _, r := range []rune{-1, utf8.MaxRune + 1} {
316 var b Builder
317 b.WriteRune(r)
318 check(t, &b, "\uFFFD")
322 var someBytes = []byte("some bytes sdljlk jsklj3lkjlk djlkjw")
324 var sinkS string
326 func benchmarkBuilder(b *testing.B, f func(b *testing.B, numWrite int, grow bool)) {
327 b.Run("1Write_NoGrow", func(b *testing.B) {
328 b.ReportAllocs()
329 f(b, 1, false)
331 b.Run("3Write_NoGrow", func(b *testing.B) {
332 b.ReportAllocs()
333 f(b, 3, false)
335 b.Run("3Write_Grow", func(b *testing.B) {
336 b.ReportAllocs()
337 f(b, 3, true)
341 func BenchmarkBuildString_Builder(b *testing.B) {
342 benchmarkBuilder(b, func(b *testing.B, numWrite int, grow bool) {
343 for i := 0; i < b.N; i++ {
344 var buf Builder
345 if grow {
346 buf.Grow(len(someBytes) * numWrite)
348 for i := 0; i < numWrite; i++ {
349 buf.Write(someBytes)
351 sinkS = buf.String()
356 func BenchmarkBuildString_ByteBuffer(b *testing.B) {
357 benchmarkBuilder(b, func(b *testing.B, numWrite int, grow bool) {
358 for i := 0; i < b.N; i++ {
359 var buf bytes.Buffer
360 if grow {
361 buf.Grow(len(someBytes) * numWrite)
363 for i := 0; i < numWrite; i++ {
364 buf.Write(someBytes)
366 sinkS = buf.String()