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 strings_test 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "strings" 13 "sync" 14 "testing" 15 ) 16 17 func TestReader(t *testing.T) { 18 r := strings.NewReader("0123456789") 19 tests := []struct { 20 off int64 21 seek int 22 n int 23 want string 24 wantpos int64 25 readerr error 26 seekerr string 27 }{ 28 {seek: io.SeekStart, off: 0, n: 20, want: "0123456789"}, 29 {seek: io.SeekStart, off: 1, n: 1, want: "1"}, 30 {seek: io.SeekCurrent, off: 1, wantpos: 3, n: 2, want: "34"}, 31 {seek: io.SeekStart, off: -1, seekerr: "strings.Reader.Seek: negative position"}, 32 {seek: io.SeekStart, off: 1 << 33, wantpos: 1 << 33, readerr: io.EOF}, 33 {seek: io.SeekCurrent, off: 1, wantpos: 1<<33 + 1, readerr: io.EOF}, 34 {seek: io.SeekStart, n: 5, want: "01234"}, 35 {seek: io.SeekCurrent, n: 5, want: "56789"}, 36 {seek: io.SeekEnd, off: -1, n: 1, wantpos: 9, want: "9"}, 37 } 38 39 for i, tt := range tests { 40 pos, err := r.Seek(tt.off, tt.seek) 41 if err == nil && tt.seekerr != "" { 42 t.Errorf("%d. want seek error %q", i, tt.seekerr) 43 continue 44 } 45 if err != nil && err.Error() != tt.seekerr { 46 t.Errorf("%d. seek error = %q; want %q", i, err.Error(), tt.seekerr) 47 continue 48 } 49 if tt.wantpos != 0 && tt.wantpos != pos { 50 t.Errorf("%d. pos = %d, want %d", i, pos, tt.wantpos) 51 } 52 buf := make([]byte, tt.n) 53 n, err := r.Read(buf) 54 if err != tt.readerr { 55 t.Errorf("%d. read = %v; want %v", i, err, tt.readerr) 56 continue 57 } 58 got := string(buf[:n]) 59 if got != tt.want { 60 t.Errorf("%d. got %q; want %q", i, got, tt.want) 61 } 62 } 63 } 64 65 func TestReadAfterBigSeek(t *testing.T) { 66 r := strings.NewReader("0123456789") 67 if _, err := r.Seek(1<<31+5, io.SeekStart); err != nil { 68 t.Fatal(err) 69 } 70 if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF { 71 t.Errorf("Read = %d, %v; want 0, EOF", n, err) 72 } 73 } 74 75 func TestReaderAt(t *testing.T) { 76 r := strings.NewReader("0123456789") 77 tests := []struct { 78 off int64 79 n int 80 want string 81 wanterr interface{} 82 }{ 83 {0, 10, "0123456789", nil}, 84 {1, 10, "123456789", io.EOF}, 85 {1, 9, "123456789", nil}, 86 {11, 10, "", io.EOF}, 87 {0, 0, "", nil}, 88 {-1, 0, "", "strings.Reader.ReadAt: negative offset"}, 89 } 90 for i, tt := range tests { 91 b := make([]byte, tt.n) 92 rn, err := r.ReadAt(b, tt.off) 93 got := string(b[:rn]) 94 if got != tt.want { 95 t.Errorf("%d. got %q; want %q", i, got, tt.want) 96 } 97 if fmt.Sprintf("%v", err) != fmt.Sprintf("%v", tt.wanterr) { 98 t.Errorf("%d. got error = %v; want %v", i, err, tt.wanterr) 99 } 100 } 101 } 102 103 func TestReaderAtConcurrent(t *testing.T) { 104 // Test for the race detector, to verify ReadAt doesn't mutate 105 // any state. 106 r := strings.NewReader("0123456789") 107 var wg sync.WaitGroup 108 for i := 0; i < 5; i++ { 109 wg.Add(1) 110 go func(i int) { 111 defer wg.Done() 112 var buf [1]byte 113 r.ReadAt(buf[:], int64(i)) 114 }(i) 115 } 116 wg.Wait() 117 } 118 119 func TestEmptyReaderConcurrent(t *testing.T) { 120 // Test for the race detector, to verify a Read that doesn't yield any bytes 121 // is okay to use from multiple goroutines. This was our historic behavior. 122 // See golang.org/issue/7856 123 r := strings.NewReader("") 124 var wg sync.WaitGroup 125 for i := 0; i < 5; i++ { 126 wg.Add(2) 127 go func() { 128 defer wg.Done() 129 var buf [1]byte 130 r.Read(buf[:]) 131 }() 132 go func() { 133 defer wg.Done() 134 r.Read(nil) 135 }() 136 } 137 wg.Wait() 138 } 139 140 func TestWriteTo(t *testing.T) { 141 const str = "0123456789" 142 for i := 0; i <= len(str); i++ { 143 s := str[i:] 144 r := strings.NewReader(s) 145 var b bytes.Buffer 146 n, err := r.WriteTo(&b) 147 if expect := int64(len(s)); n != expect { 148 t.Errorf("got %v; want %v", n, expect) 149 } 150 if err != nil { 151 t.Errorf("for length %d: got error = %v; want nil", len(s), err) 152 } 153 if b.String() != s { 154 t.Errorf("got string %q; want %q", b.String(), s) 155 } 156 if r.Len() != 0 { 157 t.Errorf("reader contains %v bytes; want 0", r.Len()) 158 } 159 } 160 } 161 162 // tests that Len is affected by reads, but Size is not. 163 func TestReaderLenSize(t *testing.T) { 164 r := strings.NewReader("abc") 165 io.CopyN(ioutil.Discard, r, 1) 166 if r.Len() != 2 { 167 t.Errorf("Len = %d; want 2", r.Len()) 168 } 169 if r.Size() != 3 { 170 t.Errorf("Size = %d; want 3", r.Size()) 171 } 172 } 173 174 func TestReaderReset(t *testing.T) { 175 r := strings.NewReader("") 176 if _, _, err := r.ReadRune(); err != nil { 177 t.Errorf("ReadRune: unexpected error: %v", err) 178 } 179 180 const want = "abcdef" 181 r.Reset(want) 182 if err := r.UnreadRune(); err == nil { 183 t.Errorf("UnreadRune: expected error, got nil") 184 } 185 buf, err := ioutil.ReadAll(r) 186 if err != nil { 187 t.Errorf("ReadAll: unexpected error: %v", err) 188 } 189 if got := string(buf); got != want { 190 t.Errorf("ReadAll: got %q, want %q", got, want) 191 } 192 } 193