annotate libgo/go/bufio/scan_test.go @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 04ced10e8804
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 // Copyright 2013 The Go Authors. All rights reserved.
kono
parents:
diff changeset
2 // Use of this source code is governed by a BSD-style
kono
parents:
diff changeset
3 // license that can be found in the LICENSE file.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 package bufio_test
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 import (
kono
parents:
diff changeset
8 . "bufio"
kono
parents:
diff changeset
9 "bytes"
kono
parents:
diff changeset
10 "errors"
kono
parents:
diff changeset
11 "io"
kono
parents:
diff changeset
12 "strings"
kono
parents:
diff changeset
13 "testing"
kono
parents:
diff changeset
14 "unicode"
kono
parents:
diff changeset
15 "unicode/utf8"
kono
parents:
diff changeset
16 )
kono
parents:
diff changeset
17
kono
parents:
diff changeset
18 const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
kono
parents:
diff changeset
19
kono
parents:
diff changeset
20 // Test white space table matches the Unicode definition.
kono
parents:
diff changeset
21 func TestSpace(t *testing.T) {
kono
parents:
diff changeset
22 for r := rune(0); r <= utf8.MaxRune; r++ {
kono
parents:
diff changeset
23 if IsSpace(r) != unicode.IsSpace(r) {
kono
parents:
diff changeset
24 t.Fatalf("white space property disagrees: %#U should be %t", r, unicode.IsSpace(r))
kono
parents:
diff changeset
25 }
kono
parents:
diff changeset
26 }
kono
parents:
diff changeset
27 }
kono
parents:
diff changeset
28
kono
parents:
diff changeset
29 var scanTests = []string{
kono
parents:
diff changeset
30 "",
kono
parents:
diff changeset
31 "a",
kono
parents:
diff changeset
32 "¼",
kono
parents:
diff changeset
33 "☹",
kono
parents:
diff changeset
34 "\x81", // UTF-8 error
kono
parents:
diff changeset
35 "\uFFFD", // correctly encoded RuneError
kono
parents:
diff changeset
36 "abcdefgh",
kono
parents:
diff changeset
37 "abc def\n\t\tgh ",
kono
parents:
diff changeset
38 "abc¼☹\x81\uFFFD日本語\x82abc",
kono
parents:
diff changeset
39 }
kono
parents:
diff changeset
40
kono
parents:
diff changeset
41 func TestScanByte(t *testing.T) {
kono
parents:
diff changeset
42 for n, test := range scanTests {
kono
parents:
diff changeset
43 buf := strings.NewReader(test)
kono
parents:
diff changeset
44 s := NewScanner(buf)
kono
parents:
diff changeset
45 s.Split(ScanBytes)
kono
parents:
diff changeset
46 var i int
kono
parents:
diff changeset
47 for i = 0; s.Scan(); i++ {
kono
parents:
diff changeset
48 if b := s.Bytes(); len(b) != 1 || b[0] != test[i] {
kono
parents:
diff changeset
49 t.Errorf("#%d: %d: expected %q got %q", n, i, test, b)
kono
parents:
diff changeset
50 }
kono
parents:
diff changeset
51 }
kono
parents:
diff changeset
52 if i != len(test) {
kono
parents:
diff changeset
53 t.Errorf("#%d: termination expected at %d; got %d", n, len(test), i)
kono
parents:
diff changeset
54 }
kono
parents:
diff changeset
55 err := s.Err()
kono
parents:
diff changeset
56 if err != nil {
kono
parents:
diff changeset
57 t.Errorf("#%d: %v", n, err)
kono
parents:
diff changeset
58 }
kono
parents:
diff changeset
59 }
kono
parents:
diff changeset
60 }
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 // Test that the rune splitter returns same sequence of runes (not bytes) as for range string.
kono
parents:
diff changeset
63 func TestScanRune(t *testing.T) {
kono
parents:
diff changeset
64 for n, test := range scanTests {
kono
parents:
diff changeset
65 buf := strings.NewReader(test)
kono
parents:
diff changeset
66 s := NewScanner(buf)
kono
parents:
diff changeset
67 s.Split(ScanRunes)
kono
parents:
diff changeset
68 var i, runeCount int
kono
parents:
diff changeset
69 var expect rune
kono
parents:
diff changeset
70 // Use a string range loop to validate the sequence of runes.
kono
parents:
diff changeset
71 for i, expect = range string(test) {
kono
parents:
diff changeset
72 if !s.Scan() {
kono
parents:
diff changeset
73 break
kono
parents:
diff changeset
74 }
kono
parents:
diff changeset
75 runeCount++
kono
parents:
diff changeset
76 got, _ := utf8.DecodeRune(s.Bytes())
kono
parents:
diff changeset
77 if got != expect {
kono
parents:
diff changeset
78 t.Errorf("#%d: %d: expected %q got %q", n, i, expect, got)
kono
parents:
diff changeset
79 }
kono
parents:
diff changeset
80 }
kono
parents:
diff changeset
81 if s.Scan() {
kono
parents:
diff changeset
82 t.Errorf("#%d: scan ran too long, got %q", n, s.Text())
kono
parents:
diff changeset
83 }
kono
parents:
diff changeset
84 testRuneCount := utf8.RuneCountInString(test)
kono
parents:
diff changeset
85 if runeCount != testRuneCount {
kono
parents:
diff changeset
86 t.Errorf("#%d: termination expected at %d; got %d", n, testRuneCount, runeCount)
kono
parents:
diff changeset
87 }
kono
parents:
diff changeset
88 err := s.Err()
kono
parents:
diff changeset
89 if err != nil {
kono
parents:
diff changeset
90 t.Errorf("#%d: %v", n, err)
kono
parents:
diff changeset
91 }
kono
parents:
diff changeset
92 }
kono
parents:
diff changeset
93 }
kono
parents:
diff changeset
94
kono
parents:
diff changeset
95 var wordScanTests = []string{
kono
parents:
diff changeset
96 "",
kono
parents:
diff changeset
97 " ",
kono
parents:
diff changeset
98 "\n",
kono
parents:
diff changeset
99 "a",
kono
parents:
diff changeset
100 " a ",
kono
parents:
diff changeset
101 "abc def",
kono
parents:
diff changeset
102 " abc def ",
kono
parents:
diff changeset
103 " abc\tdef\nghi\rjkl\fmno\vpqr\u0085stu\u00a0\n",
kono
parents:
diff changeset
104 }
kono
parents:
diff changeset
105
kono
parents:
diff changeset
106 // Test that the word splitter returns the same data as strings.Fields.
kono
parents:
diff changeset
107 func TestScanWords(t *testing.T) {
kono
parents:
diff changeset
108 for n, test := range wordScanTests {
kono
parents:
diff changeset
109 buf := strings.NewReader(test)
kono
parents:
diff changeset
110 s := NewScanner(buf)
kono
parents:
diff changeset
111 s.Split(ScanWords)
kono
parents:
diff changeset
112 words := strings.Fields(test)
kono
parents:
diff changeset
113 var wordCount int
kono
parents:
diff changeset
114 for wordCount = 0; wordCount < len(words); wordCount++ {
kono
parents:
diff changeset
115 if !s.Scan() {
kono
parents:
diff changeset
116 break
kono
parents:
diff changeset
117 }
kono
parents:
diff changeset
118 got := s.Text()
kono
parents:
diff changeset
119 if got != words[wordCount] {
kono
parents:
diff changeset
120 t.Errorf("#%d: %d: expected %q got %q", n, wordCount, words[wordCount], got)
kono
parents:
diff changeset
121 }
kono
parents:
diff changeset
122 }
kono
parents:
diff changeset
123 if s.Scan() {
kono
parents:
diff changeset
124 t.Errorf("#%d: scan ran too long, got %q", n, s.Text())
kono
parents:
diff changeset
125 }
kono
parents:
diff changeset
126 if wordCount != len(words) {
kono
parents:
diff changeset
127 t.Errorf("#%d: termination expected at %d; got %d", n, len(words), wordCount)
kono
parents:
diff changeset
128 }
kono
parents:
diff changeset
129 err := s.Err()
kono
parents:
diff changeset
130 if err != nil {
kono
parents:
diff changeset
131 t.Errorf("#%d: %v", n, err)
kono
parents:
diff changeset
132 }
kono
parents:
diff changeset
133 }
kono
parents:
diff changeset
134 }
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 // slowReader is a reader that returns only a few bytes at a time, to test the incremental
kono
parents:
diff changeset
137 // reads in Scanner.Scan.
kono
parents:
diff changeset
138 type slowReader struct {
kono
parents:
diff changeset
139 max int
kono
parents:
diff changeset
140 buf io.Reader
kono
parents:
diff changeset
141 }
kono
parents:
diff changeset
142
kono
parents:
diff changeset
143 func (sr *slowReader) Read(p []byte) (n int, err error) {
kono
parents:
diff changeset
144 if len(p) > sr.max {
kono
parents:
diff changeset
145 p = p[0:sr.max]
kono
parents:
diff changeset
146 }
kono
parents:
diff changeset
147 return sr.buf.Read(p)
kono
parents:
diff changeset
148 }
kono
parents:
diff changeset
149
kono
parents:
diff changeset
150 // genLine writes to buf a predictable but non-trivial line of text of length
kono
parents:
diff changeset
151 // n, including the terminal newline and an occasional carriage return.
kono
parents:
diff changeset
152 // If addNewline is false, the \r and \n are not emitted.
kono
parents:
diff changeset
153 func genLine(buf *bytes.Buffer, lineNum, n int, addNewline bool) {
kono
parents:
diff changeset
154 buf.Reset()
kono
parents:
diff changeset
155 doCR := lineNum%5 == 0
kono
parents:
diff changeset
156 if doCR {
kono
parents:
diff changeset
157 n--
kono
parents:
diff changeset
158 }
kono
parents:
diff changeset
159 for i := 0; i < n-1; i++ { // Stop early for \n.
kono
parents:
diff changeset
160 c := 'a' + byte(lineNum+i)
kono
parents:
diff changeset
161 if c == '\n' || c == '\r' { // Don't confuse us.
kono
parents:
diff changeset
162 c = 'N'
kono
parents:
diff changeset
163 }
kono
parents:
diff changeset
164 buf.WriteByte(c)
kono
parents:
diff changeset
165 }
kono
parents:
diff changeset
166 if addNewline {
kono
parents:
diff changeset
167 if doCR {
kono
parents:
diff changeset
168 buf.WriteByte('\r')
kono
parents:
diff changeset
169 }
kono
parents:
diff changeset
170 buf.WriteByte('\n')
kono
parents:
diff changeset
171 }
kono
parents:
diff changeset
172 }
kono
parents:
diff changeset
173
kono
parents:
diff changeset
174 // Test the line splitter, including some carriage returns but no long lines.
kono
parents:
diff changeset
175 func TestScanLongLines(t *testing.T) {
kono
parents:
diff changeset
176 // Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize.
kono
parents:
diff changeset
177 tmp := new(bytes.Buffer)
kono
parents:
diff changeset
178 buf := new(bytes.Buffer)
kono
parents:
diff changeset
179 lineNum := 0
kono
parents:
diff changeset
180 j := 0
kono
parents:
diff changeset
181 for i := 0; i < 2*smallMaxTokenSize; i++ {
kono
parents:
diff changeset
182 genLine(tmp, lineNum, j, true)
kono
parents:
diff changeset
183 if j < smallMaxTokenSize {
kono
parents:
diff changeset
184 j++
kono
parents:
diff changeset
185 } else {
kono
parents:
diff changeset
186 j--
kono
parents:
diff changeset
187 }
kono
parents:
diff changeset
188 buf.Write(tmp.Bytes())
kono
parents:
diff changeset
189 lineNum++
kono
parents:
diff changeset
190 }
kono
parents:
diff changeset
191 s := NewScanner(&slowReader{1, buf})
kono
parents:
diff changeset
192 s.Split(ScanLines)
kono
parents:
diff changeset
193 s.MaxTokenSize(smallMaxTokenSize)
kono
parents:
diff changeset
194 j = 0
kono
parents:
diff changeset
195 for lineNum := 0; s.Scan(); lineNum++ {
kono
parents:
diff changeset
196 genLine(tmp, lineNum, j, false)
kono
parents:
diff changeset
197 if j < smallMaxTokenSize {
kono
parents:
diff changeset
198 j++
kono
parents:
diff changeset
199 } else {
kono
parents:
diff changeset
200 j--
kono
parents:
diff changeset
201 }
kono
parents:
diff changeset
202 line := tmp.String() // We use the string-valued token here, for variety.
kono
parents:
diff changeset
203 if s.Text() != line {
kono
parents:
diff changeset
204 t.Errorf("%d: bad line: %d %d\n%.100q\n%.100q\n", lineNum, len(s.Bytes()), len(line), s.Text(), line)
kono
parents:
diff changeset
205 }
kono
parents:
diff changeset
206 }
kono
parents:
diff changeset
207 err := s.Err()
kono
parents:
diff changeset
208 if err != nil {
kono
parents:
diff changeset
209 t.Fatal(err)
kono
parents:
diff changeset
210 }
kono
parents:
diff changeset
211 }
kono
parents:
diff changeset
212
kono
parents:
diff changeset
213 // Test that the line splitter errors out on a long line.
kono
parents:
diff changeset
214 func TestScanLineTooLong(t *testing.T) {
kono
parents:
diff changeset
215 const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
kono
parents:
diff changeset
216 // Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize.
kono
parents:
diff changeset
217 tmp := new(bytes.Buffer)
kono
parents:
diff changeset
218 buf := new(bytes.Buffer)
kono
parents:
diff changeset
219 lineNum := 0
kono
parents:
diff changeset
220 j := 0
kono
parents:
diff changeset
221 for i := 0; i < 2*smallMaxTokenSize; i++ {
kono
parents:
diff changeset
222 genLine(tmp, lineNum, j, true)
kono
parents:
diff changeset
223 j++
kono
parents:
diff changeset
224 buf.Write(tmp.Bytes())
kono
parents:
diff changeset
225 lineNum++
kono
parents:
diff changeset
226 }
kono
parents:
diff changeset
227 s := NewScanner(&slowReader{3, buf})
kono
parents:
diff changeset
228 s.Split(ScanLines)
kono
parents:
diff changeset
229 s.MaxTokenSize(smallMaxTokenSize)
kono
parents:
diff changeset
230 j = 0
kono
parents:
diff changeset
231 for lineNum := 0; s.Scan(); lineNum++ {
kono
parents:
diff changeset
232 genLine(tmp, lineNum, j, false)
kono
parents:
diff changeset
233 if j < smallMaxTokenSize {
kono
parents:
diff changeset
234 j++
kono
parents:
diff changeset
235 } else {
kono
parents:
diff changeset
236 j--
kono
parents:
diff changeset
237 }
kono
parents:
diff changeset
238 line := tmp.Bytes()
kono
parents:
diff changeset
239 if !bytes.Equal(s.Bytes(), line) {
kono
parents:
diff changeset
240 t.Errorf("%d: bad line: %d %d\n%.100q\n%.100q\n", lineNum, len(s.Bytes()), len(line), s.Bytes(), line)
kono
parents:
diff changeset
241 }
kono
parents:
diff changeset
242 }
kono
parents:
diff changeset
243 err := s.Err()
kono
parents:
diff changeset
244 if err != ErrTooLong {
kono
parents:
diff changeset
245 t.Fatalf("expected ErrTooLong; got %s", err)
kono
parents:
diff changeset
246 }
kono
parents:
diff changeset
247 }
kono
parents:
diff changeset
248
kono
parents:
diff changeset
249 // Test that the line splitter handles a final line without a newline.
kono
parents:
diff changeset
250 func testNoNewline(text string, lines []string, t *testing.T) {
kono
parents:
diff changeset
251 buf := strings.NewReader(text)
kono
parents:
diff changeset
252 s := NewScanner(&slowReader{7, buf})
kono
parents:
diff changeset
253 s.Split(ScanLines)
kono
parents:
diff changeset
254 for lineNum := 0; s.Scan(); lineNum++ {
kono
parents:
diff changeset
255 line := lines[lineNum]
kono
parents:
diff changeset
256 if s.Text() != line {
kono
parents:
diff changeset
257 t.Errorf("%d: bad line: %d %d\n%.100q\n%.100q\n", lineNum, len(s.Bytes()), len(line), s.Bytes(), line)
kono
parents:
diff changeset
258 }
kono
parents:
diff changeset
259 }
kono
parents:
diff changeset
260 err := s.Err()
kono
parents:
diff changeset
261 if err != nil {
kono
parents:
diff changeset
262 t.Fatal(err)
kono
parents:
diff changeset
263 }
kono
parents:
diff changeset
264 }
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 // Test that the line splitter handles a final line without a newline.
kono
parents:
diff changeset
267 func TestScanLineNoNewline(t *testing.T) {
kono
parents:
diff changeset
268 const text = "abcdefghijklmn\nopqrstuvwxyz"
kono
parents:
diff changeset
269 lines := []string{
kono
parents:
diff changeset
270 "abcdefghijklmn",
kono
parents:
diff changeset
271 "opqrstuvwxyz",
kono
parents:
diff changeset
272 }
kono
parents:
diff changeset
273 testNoNewline(text, lines, t)
kono
parents:
diff changeset
274 }
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 // Test that the line splitter handles a final line with a carriage return but no newline.
kono
parents:
diff changeset
277 func TestScanLineReturnButNoNewline(t *testing.T) {
kono
parents:
diff changeset
278 const text = "abcdefghijklmn\nopqrstuvwxyz\r"
kono
parents:
diff changeset
279 lines := []string{
kono
parents:
diff changeset
280 "abcdefghijklmn",
kono
parents:
diff changeset
281 "opqrstuvwxyz",
kono
parents:
diff changeset
282 }
kono
parents:
diff changeset
283 testNoNewline(text, lines, t)
kono
parents:
diff changeset
284 }
kono
parents:
diff changeset
285
kono
parents:
diff changeset
286 // Test that the line splitter handles a final empty line.
kono
parents:
diff changeset
287 func TestScanLineEmptyFinalLine(t *testing.T) {
kono
parents:
diff changeset
288 const text = "abcdefghijklmn\nopqrstuvwxyz\n\n"
kono
parents:
diff changeset
289 lines := []string{
kono
parents:
diff changeset
290 "abcdefghijklmn",
kono
parents:
diff changeset
291 "opqrstuvwxyz",
kono
parents:
diff changeset
292 "",
kono
parents:
diff changeset
293 }
kono
parents:
diff changeset
294 testNoNewline(text, lines, t)
kono
parents:
diff changeset
295 }
kono
parents:
diff changeset
296
kono
parents:
diff changeset
297 // Test that the line splitter handles a final empty line with a carriage return but no newline.
kono
parents:
diff changeset
298 func TestScanLineEmptyFinalLineWithCR(t *testing.T) {
kono
parents:
diff changeset
299 const text = "abcdefghijklmn\nopqrstuvwxyz\n\r"
kono
parents:
diff changeset
300 lines := []string{
kono
parents:
diff changeset
301 "abcdefghijklmn",
kono
parents:
diff changeset
302 "opqrstuvwxyz",
kono
parents:
diff changeset
303 "",
kono
parents:
diff changeset
304 }
kono
parents:
diff changeset
305 testNoNewline(text, lines, t)
kono
parents:
diff changeset
306 }
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 var testError = errors.New("testError")
kono
parents:
diff changeset
309
kono
parents:
diff changeset
310 // Test the correct error is returned when the split function errors out.
kono
parents:
diff changeset
311 func TestSplitError(t *testing.T) {
kono
parents:
diff changeset
312 // Create a split function that delivers a little data, then a predictable error.
kono
parents:
diff changeset
313 numSplits := 0
kono
parents:
diff changeset
314 const okCount = 7
kono
parents:
diff changeset
315 errorSplit := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
kono
parents:
diff changeset
316 if atEOF {
kono
parents:
diff changeset
317 panic("didn't get enough data")
kono
parents:
diff changeset
318 }
kono
parents:
diff changeset
319 if numSplits >= okCount {
kono
parents:
diff changeset
320 return 0, nil, testError
kono
parents:
diff changeset
321 }
kono
parents:
diff changeset
322 numSplits++
kono
parents:
diff changeset
323 return 1, data[0:1], nil
kono
parents:
diff changeset
324 }
kono
parents:
diff changeset
325 // Read the data.
kono
parents:
diff changeset
326 const text = "abcdefghijklmnopqrstuvwxyz"
kono
parents:
diff changeset
327 buf := strings.NewReader(text)
kono
parents:
diff changeset
328 s := NewScanner(&slowReader{1, buf})
kono
parents:
diff changeset
329 s.Split(errorSplit)
kono
parents:
diff changeset
330 var i int
kono
parents:
diff changeset
331 for i = 0; s.Scan(); i++ {
kono
parents:
diff changeset
332 if len(s.Bytes()) != 1 || text[i] != s.Bytes()[0] {
kono
parents:
diff changeset
333 t.Errorf("#%d: expected %q got %q", i, text[i], s.Bytes()[0])
kono
parents:
diff changeset
334 }
kono
parents:
diff changeset
335 }
kono
parents:
diff changeset
336 // Check correct termination location and error.
kono
parents:
diff changeset
337 if i != okCount {
kono
parents:
diff changeset
338 t.Errorf("unexpected termination; expected %d tokens got %d", okCount, i)
kono
parents:
diff changeset
339 }
kono
parents:
diff changeset
340 err := s.Err()
kono
parents:
diff changeset
341 if err != testError {
kono
parents:
diff changeset
342 t.Fatalf("expected %q got %v", testError, err)
kono
parents:
diff changeset
343 }
kono
parents:
diff changeset
344 }
kono
parents:
diff changeset
345
kono
parents:
diff changeset
346 // Test that an EOF is overridden by a user-generated scan error.
kono
parents:
diff changeset
347 func TestErrAtEOF(t *testing.T) {
kono
parents:
diff changeset
348 s := NewScanner(strings.NewReader("1 2 33"))
kono
parents:
diff changeset
349 // This splitter will fail on last entry, after s.err==EOF.
kono
parents:
diff changeset
350 split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
kono
parents:
diff changeset
351 advance, token, err = ScanWords(data, atEOF)
kono
parents:
diff changeset
352 if len(token) > 1 {
kono
parents:
diff changeset
353 if s.ErrOrEOF() != io.EOF {
kono
parents:
diff changeset
354 t.Fatal("not testing EOF")
kono
parents:
diff changeset
355 }
kono
parents:
diff changeset
356 err = testError
kono
parents:
diff changeset
357 }
kono
parents:
diff changeset
358 return
kono
parents:
diff changeset
359 }
kono
parents:
diff changeset
360 s.Split(split)
kono
parents:
diff changeset
361 for s.Scan() {
kono
parents:
diff changeset
362 }
kono
parents:
diff changeset
363 if s.Err() != testError {
kono
parents:
diff changeset
364 t.Fatal("wrong error:", s.Err())
kono
parents:
diff changeset
365 }
kono
parents:
diff changeset
366 }
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 // Test for issue 5268.
kono
parents:
diff changeset
369 type alwaysError struct{}
kono
parents:
diff changeset
370
kono
parents:
diff changeset
371 func (alwaysError) Read(p []byte) (int, error) {
kono
parents:
diff changeset
372 return 0, io.ErrUnexpectedEOF
kono
parents:
diff changeset
373 }
kono
parents:
diff changeset
374
kono
parents:
diff changeset
375 func TestNonEOFWithEmptyRead(t *testing.T) {
kono
parents:
diff changeset
376 scanner := NewScanner(alwaysError{})
kono
parents:
diff changeset
377 for scanner.Scan() {
kono
parents:
diff changeset
378 t.Fatal("read should fail")
kono
parents:
diff changeset
379 }
kono
parents:
diff changeset
380 err := scanner.Err()
kono
parents:
diff changeset
381 if err != io.ErrUnexpectedEOF {
kono
parents:
diff changeset
382 t.Errorf("unexpected error: %v", err)
kono
parents:
diff changeset
383 }
kono
parents:
diff changeset
384 }
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 // Test that Scan finishes if we have endless empty reads.
kono
parents:
diff changeset
387 type endlessZeros struct{}
kono
parents:
diff changeset
388
kono
parents:
diff changeset
389 func (endlessZeros) Read(p []byte) (int, error) {
kono
parents:
diff changeset
390 return 0, nil
kono
parents:
diff changeset
391 }
kono
parents:
diff changeset
392
kono
parents:
diff changeset
393 func TestBadReader(t *testing.T) {
kono
parents:
diff changeset
394 scanner := NewScanner(endlessZeros{})
kono
parents:
diff changeset
395 for scanner.Scan() {
kono
parents:
diff changeset
396 t.Fatal("read should fail")
kono
parents:
diff changeset
397 }
kono
parents:
diff changeset
398 err := scanner.Err()
kono
parents:
diff changeset
399 if err != io.ErrNoProgress {
kono
parents:
diff changeset
400 t.Errorf("unexpected error: %v", err)
kono
parents:
diff changeset
401 }
kono
parents:
diff changeset
402 }
kono
parents:
diff changeset
403
kono
parents:
diff changeset
404 func TestScanWordsExcessiveWhiteSpace(t *testing.T) {
kono
parents:
diff changeset
405 const word = "ipsum"
kono
parents:
diff changeset
406 s := strings.Repeat(" ", 4*smallMaxTokenSize) + word
kono
parents:
diff changeset
407 scanner := NewScanner(strings.NewReader(s))
kono
parents:
diff changeset
408 scanner.MaxTokenSize(smallMaxTokenSize)
kono
parents:
diff changeset
409 scanner.Split(ScanWords)
kono
parents:
diff changeset
410 if !scanner.Scan() {
kono
parents:
diff changeset
411 t.Fatalf("scan failed: %v", scanner.Err())
kono
parents:
diff changeset
412 }
kono
parents:
diff changeset
413 if token := scanner.Text(); token != word {
kono
parents:
diff changeset
414 t.Fatalf("unexpected token: %v", token)
kono
parents:
diff changeset
415 }
kono
parents:
diff changeset
416 }
kono
parents:
diff changeset
417
kono
parents:
diff changeset
418 // Test that empty tokens, including at end of line or end of file, are found by the scanner.
kono
parents:
diff changeset
419 // Issue 8672: Could miss final empty token.
kono
parents:
diff changeset
420
kono
parents:
diff changeset
421 func commaSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
kono
parents:
diff changeset
422 for i := 0; i < len(data); i++ {
kono
parents:
diff changeset
423 if data[i] == ',' {
kono
parents:
diff changeset
424 return i + 1, data[:i], nil
kono
parents:
diff changeset
425 }
kono
parents:
diff changeset
426 }
kono
parents:
diff changeset
427 return 0, data, ErrFinalToken
kono
parents:
diff changeset
428 }
kono
parents:
diff changeset
429
kono
parents:
diff changeset
430 func testEmptyTokens(t *testing.T, text string, values []string) {
kono
parents:
diff changeset
431 s := NewScanner(strings.NewReader(text))
kono
parents:
diff changeset
432 s.Split(commaSplit)
kono
parents:
diff changeset
433 var i int
kono
parents:
diff changeset
434 for i = 0; s.Scan(); i++ {
kono
parents:
diff changeset
435 if i >= len(values) {
kono
parents:
diff changeset
436 t.Fatalf("got %d fields, expected %d", i+1, len(values))
kono
parents:
diff changeset
437 }
kono
parents:
diff changeset
438 if s.Text() != values[i] {
kono
parents:
diff changeset
439 t.Errorf("%d: expected %q got %q", i, values[i], s.Text())
kono
parents:
diff changeset
440 }
kono
parents:
diff changeset
441 }
kono
parents:
diff changeset
442 if i != len(values) {
kono
parents:
diff changeset
443 t.Fatalf("got %d fields, expected %d", i, len(values))
kono
parents:
diff changeset
444 }
kono
parents:
diff changeset
445 if err := s.Err(); err != nil {
kono
parents:
diff changeset
446 t.Fatal(err)
kono
parents:
diff changeset
447 }
kono
parents:
diff changeset
448 }
kono
parents:
diff changeset
449
kono
parents:
diff changeset
450 func TestEmptyTokens(t *testing.T) {
kono
parents:
diff changeset
451 testEmptyTokens(t, "1,2,3,", []string{"1", "2", "3", ""})
kono
parents:
diff changeset
452 }
kono
parents:
diff changeset
453
kono
parents:
diff changeset
454 func TestWithNoEmptyTokens(t *testing.T) {
kono
parents:
diff changeset
455 testEmptyTokens(t, "1,2,3", []string{"1", "2", "3"})
kono
parents:
diff changeset
456 }
kono
parents:
diff changeset
457
kono
parents:
diff changeset
458 func loopAtEOFSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
kono
parents:
diff changeset
459 if len(data) > 0 {
kono
parents:
diff changeset
460 return 1, data[:1], nil
kono
parents:
diff changeset
461 }
kono
parents:
diff changeset
462 return 0, data, nil
kono
parents:
diff changeset
463 }
kono
parents:
diff changeset
464
kono
parents:
diff changeset
465 func TestDontLoopForever(t *testing.T) {
kono
parents:
diff changeset
466 s := NewScanner(strings.NewReader("abc"))
kono
parents:
diff changeset
467 s.Split(loopAtEOFSplit)
kono
parents:
diff changeset
468 // Expect a panic
kono
parents:
diff changeset
469 defer func() {
kono
parents:
diff changeset
470 err := recover()
kono
parents:
diff changeset
471 if err == nil {
kono
parents:
diff changeset
472 t.Fatal("should have panicked")
kono
parents:
diff changeset
473 }
kono
parents:
diff changeset
474 if msg, ok := err.(string); !ok || !strings.Contains(msg, "empty tokens") {
kono
parents:
diff changeset
475 panic(err)
kono
parents:
diff changeset
476 }
kono
parents:
diff changeset
477 }()
kono
parents:
diff changeset
478 for count := 0; s.Scan(); count++ {
kono
parents:
diff changeset
479 if count > 1000 {
kono
parents:
diff changeset
480 t.Fatal("looping")
kono
parents:
diff changeset
481 }
kono
parents:
diff changeset
482 }
kono
parents:
diff changeset
483 if s.Err() != nil {
kono
parents:
diff changeset
484 t.Fatal("after scan:", s.Err())
kono
parents:
diff changeset
485 }
kono
parents:
diff changeset
486 }
kono
parents:
diff changeset
487
kono
parents:
diff changeset
488 func TestBlankLines(t *testing.T) {
kono
parents:
diff changeset
489 s := NewScanner(strings.NewReader(strings.Repeat("\n", 1000)))
kono
parents:
diff changeset
490 for count := 0; s.Scan(); count++ {
kono
parents:
diff changeset
491 if count > 2000 {
kono
parents:
diff changeset
492 t.Fatal("looping")
kono
parents:
diff changeset
493 }
kono
parents:
diff changeset
494 }
kono
parents:
diff changeset
495 if s.Err() != nil {
kono
parents:
diff changeset
496 t.Fatal("after scan:", s.Err())
kono
parents:
diff changeset
497 }
kono
parents:
diff changeset
498 }
kono
parents:
diff changeset
499
kono
parents:
diff changeset
500 type countdown int
kono
parents:
diff changeset
501
kono
parents:
diff changeset
502 func (c *countdown) split(data []byte, atEOF bool) (advance int, token []byte, err error) {
kono
parents:
diff changeset
503 if *c > 0 {
kono
parents:
diff changeset
504 *c--
kono
parents:
diff changeset
505 return 1, data[:1], nil
kono
parents:
diff changeset
506 }
kono
parents:
diff changeset
507 return 0, nil, nil
kono
parents:
diff changeset
508 }
kono
parents:
diff changeset
509
kono
parents:
diff changeset
510 // Check that the looping-at-EOF check doesn't trigger for merely empty tokens.
kono
parents:
diff changeset
511 func TestEmptyLinesOK(t *testing.T) {
kono
parents:
diff changeset
512 c := countdown(10000)
kono
parents:
diff changeset
513 s := NewScanner(strings.NewReader(strings.Repeat("\n", 10000)))
kono
parents:
diff changeset
514 s.Split(c.split)
kono
parents:
diff changeset
515 for s.Scan() {
kono
parents:
diff changeset
516 }
kono
parents:
diff changeset
517 if s.Err() != nil {
kono
parents:
diff changeset
518 t.Fatal("after scan:", s.Err())
kono
parents:
diff changeset
519 }
kono
parents:
diff changeset
520 if c != 0 {
kono
parents:
diff changeset
521 t.Fatalf("stopped with %d left to process", c)
kono
parents:
diff changeset
522 }
kono
parents:
diff changeset
523 }
kono
parents:
diff changeset
524
kono
parents:
diff changeset
525 // Make sure we can read a huge token if a big enough buffer is provided.
kono
parents:
diff changeset
526 func TestHugeBuffer(t *testing.T) {
kono
parents:
diff changeset
527 text := strings.Repeat("x", 2*MaxScanTokenSize)
kono
parents:
diff changeset
528 s := NewScanner(strings.NewReader(text + "\n"))
kono
parents:
diff changeset
529 s.Buffer(make([]byte, 100), 3*MaxScanTokenSize)
kono
parents:
diff changeset
530 for s.Scan() {
kono
parents:
diff changeset
531 token := s.Text()
kono
parents:
diff changeset
532 if token != text {
kono
parents:
diff changeset
533 t.Errorf("scan got incorrect token of length %d", len(token))
kono
parents:
diff changeset
534 }
kono
parents:
diff changeset
535 }
kono
parents:
diff changeset
536 if s.Err() != nil {
kono
parents:
diff changeset
537 t.Fatal("after scan:", s.Err())
kono
parents:
diff changeset
538 }
kono
parents:
diff changeset
539 }