]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgo/go/fmt/scan_test.go
libgo: Update to current sources.
[thirdparty/gcc.git] / libgo / go / fmt / scan_test.go
CommitLineData
7a938933
ILT
1// Copyright 2009 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
5package fmt_test
6
7import (
8 "bufio"
5133f00e 9 "bytes"
2fd401c8 10 "errors"
7a938933
ILT
11 . "fmt"
12 "io"
ff5f50c5 13 "math"
7a938933
ILT
14 "reflect"
15 "regexp"
16 "strings"
17 "testing"
9c63abc9 18 "unicode/utf8"
7a938933
ILT
19)
20
21type ScanTest struct {
22 text string
23 in interface{}
24 out interface{}
25}
26
27type ScanfTest struct {
28 format string
29 text string
30 in interface{}
31 out interface{}
32}
33
34type ScanfMultiTest struct {
35 format string
36 text string
37 in []interface{}
38 out []interface{}
39 err string
40}
41
42var (
43 boolVal bool
44 intVal int
45 int8Val int8
46 int16Val int16
47 int32Val int32
48 int64Val int64
49 uintVal uint
50 uint8Val uint8
51 uint16Val uint16
52 uint32Val uint32
53 uint64Val uint64
7a938933
ILT
54 float32Val float32
55 float64Val float64
56 stringVal string
57 stringVal1 string
58 bytesVal []byte
9a0e3259 59 runeVal rune
7a938933
ILT
60 complex64Val complex64
61 complex128Val complex128
62 renamedBoolVal renamedBool
63 renamedIntVal renamedInt
64 renamedInt8Val renamedInt8
65 renamedInt16Val renamedInt16
66 renamedInt32Val renamedInt32
67 renamedInt64Val renamedInt64
68 renamedUintVal renamedUint
69 renamedUint8Val renamedUint8
70 renamedUint16Val renamedUint16
71 renamedUint32Val renamedUint32
72 renamedUint64Val renamedUint64
73 renamedUintptrVal renamedUintptr
74 renamedStringVal renamedString
75 renamedBytesVal renamedBytes
7a938933
ILT
76 renamedFloat32Val renamedFloat32
77 renamedFloat64Val renamedFloat64
7a938933
ILT
78 renamedComplex64Val renamedComplex64
79 renamedComplex128Val renamedComplex128
80)
81
ff5f50c5
ILT
82type FloatTest struct {
83 text string
84 in float64
85 out float64
86}
87
7a938933
ILT
88// Xs accepts any non-empty run of the verb character
89type Xs string
90
2fd401c8 91func (x *Xs) Scan(state ScanState, verb rune) error {
506cf9aa 92 tok, err := state.Token(true, func(r rune) bool { return r == verb })
7a938933
ILT
93 if err != nil {
94 return err
95 }
8039ca76
ILT
96 s := string(tok)
97 if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(s) {
2fd401c8 98 return errors.New("syntax error for xs")
7a938933 99 }
8039ca76 100 *x = Xs(s)
7a938933
ILT
101 return nil
102}
103
104var xVal Xs
105
5133f00e
ILT
106// IntString accepts an integer followed immediately by a string.
107// It tests the embedding of a scan within a scan.
108type IntString struct {
109 i int
110 s string
111}
112
2fd401c8 113func (s *IntString) Scan(state ScanState, verb rune) error {
5133f00e
ILT
114 if _, err := Fscan(state, &s.i); err != nil {
115 return err
116 }
117
8039ca76
ILT
118 tok, err := state.Token(true, nil)
119 if err != nil {
5133f00e
ILT
120 return err
121 }
8039ca76 122 s.s = string(tok)
5133f00e
ILT
123 return nil
124}
125
126var intStringVal IntString
127
7a938933
ILT
128// myStringReader implements Read but not ReadRune, allowing us to test our readRune wrapper
129// type that creates something that can read runes given only Read().
130type myStringReader struct {
131 r *strings.Reader
132}
133
2fd401c8 134func (s *myStringReader) Read(p []byte) (n int, err error) {
7a938933
ILT
135 return s.r.Read(p)
136}
137
138func newReader(s string) *myStringReader {
139 return &myStringReader{strings.NewReader(s)}
140}
141
142var scanTests = []ScanTest{
5133f00e 143 // Basic types
7a938933
ILT
144 {"T\n", &boolVal, true}, // boolean test vals toggle to be sure they are written
145 {"F\n", &boolVal, false}, // restored to zero value
146 {"21\n", &intVal, 21},
5133f00e
ILT
147 {"0\n", &intVal, 0},
148 {"000\n", &intVal, 0},
149 {"0x10\n", &intVal, 0x10},
150 {"-0x10\n", &intVal, -0x10},
151 {"0377\n", &intVal, 0377},
152 {"-0377\n", &intVal, -0377},
153 {"0\n", &uintVal, uint(0)},
154 {"000\n", &uintVal, uint(0)},
155 {"0x10\n", &uintVal, uint(0x10)},
156 {"0377\n", &uintVal, uint(0377)},
7a938933
ILT
157 {"22\n", &int8Val, int8(22)},
158 {"23\n", &int16Val, int16(23)},
159 {"24\n", &int32Val, int32(24)},
160 {"25\n", &int64Val, int64(25)},
161 {"127\n", &int8Val, int8(127)},
162 {"-21\n", &intVal, -21},
163 {"-22\n", &int8Val, int8(-22)},
164 {"-23\n", &int16Val, int16(-23)},
165 {"-24\n", &int32Val, int32(-24)},
166 {"-25\n", &int64Val, int64(-25)},
167 {"-128\n", &int8Val, int8(-128)},
168 {"+21\n", &intVal, +21},
169 {"+22\n", &int8Val, int8(+22)},
170 {"+23\n", &int16Val, int16(+23)},
171 {"+24\n", &int32Val, int32(+24)},
172 {"+25\n", &int64Val, int64(+25)},
173 {"+127\n", &int8Val, int8(+127)},
174 {"26\n", &uintVal, uint(26)},
175 {"27\n", &uint8Val, uint8(27)},
176 {"28\n", &uint16Val, uint16(28)},
177 {"29\n", &uint32Val, uint32(29)},
178 {"30\n", &uint64Val, uint64(30)},
179 {"255\n", &uint8Val, uint8(255)},
180 {"32767\n", &int16Val, int16(32767)},
ff5f50c5 181 {"2.3\n", &float64Val, 2.3},
7a938933 182 {"2.3e1\n", &float32Val, float32(2.3e1)},
ff5f50c5 183 {"2.3e2\n", &float64Val, 2.3e2},
5133f00e
ILT
184 {"2.3p2\n", &float64Val, 2.3 * 4},
185 {"2.3p+2\n", &float64Val, 2.3 * 4},
186 {"2.3p+66\n", &float64Val, 2.3 * (1 << 32) * (1 << 32) * 4},
187 {"2.3p-66\n", &float64Val, 2.3 / ((1 << 32) * (1 << 32) * 4)},
7a938933
ILT
188 {"2.35\n", &stringVal, "2.35"},
189 {"2345678\n", &bytesVal, []byte("2345678")},
ff5f50c5 190 {"(3.4e1-2i)\n", &complex128Val, 3.4e1 - 2i},
7a938933
ILT
191 {"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)},
192 {"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)},
193 {"hello\n", &stringVal, "hello"},
194
195 // Renamed types
196 {"true\n", &renamedBoolVal, renamedBool(true)},
197 {"F\n", &renamedBoolVal, renamedBool(false)},
198 {"101\n", &renamedIntVal, renamedInt(101)},
199 {"102\n", &renamedIntVal, renamedInt(102)},
200 {"103\n", &renamedUintVal, renamedUint(103)},
201 {"104\n", &renamedUintVal, renamedUint(104)},
202 {"105\n", &renamedInt8Val, renamedInt8(105)},
203 {"106\n", &renamedInt16Val, renamedInt16(106)},
204 {"107\n", &renamedInt32Val, renamedInt32(107)},
205 {"108\n", &renamedInt64Val, renamedInt64(108)},
206 {"109\n", &renamedUint8Val, renamedUint8(109)},
207 {"110\n", &renamedUint16Val, renamedUint16(110)},
208 {"111\n", &renamedUint32Val, renamedUint32(111)},
209 {"112\n", &renamedUint64Val, renamedUint64(112)},
210 {"113\n", &renamedUintptrVal, renamedUintptr(113)},
211 {"114\n", &renamedStringVal, renamedString("114")},
212 {"115\n", &renamedBytesVal, renamedBytes([]byte("115"))},
213
5133f00e 214 // Custom scanners.
7a938933 215 {" vvv ", &xVal, Xs("vvv")},
5133f00e 216 {" 1234hello", &intStringVal, IntString{1234, "hello"}},
7a938933
ILT
217
218 // Fixed bugs
219 {"2147483648\n", &int64Val, int64(2147483648)}, // was: integer overflow
220}
221
222var scanfTests = []ScanfTest{
223 {"%v", "TRUE\n", &boolVal, true},
224 {"%t", "false\n", &boolVal, false},
225 {"%v", "-71\n", &intVal, -71},
5133f00e
ILT
226 {"%v", "0377\n", &intVal, 0377},
227 {"%v", "0x44\n", &intVal, 0x44},
7a938933 228 {"%d", "72\n", &intVal, 72},
9a0e3259
ILT
229 {"%c", "a\n", &runeVal, 'a'},
230 {"%c", "\u5072\n", &runeVal, '\u5072'},
231 {"%c", "\u1234\n", &runeVal, '\u1234'},
7a938933
ILT
232 {"%d", "73\n", &int8Val, int8(73)},
233 {"%d", "+74\n", &int16Val, int16(74)},
234 {"%d", "75\n", &int32Val, int32(75)},
235 {"%d", "76\n", &int64Val, int64(76)},
236 {"%b", "1001001\n", &intVal, 73},
237 {"%o", "075\n", &intVal, 075},
238 {"%x", "a75\n", &intVal, 0xa75},
239 {"%v", "71\n", &uintVal, uint(71)},
240 {"%d", "72\n", &uintVal, uint(72)},
241 {"%d", "73\n", &uint8Val, uint8(73)},
242 {"%d", "74\n", &uint16Val, uint16(74)},
243 {"%d", "75\n", &uint32Val, uint32(75)},
244 {"%d", "76\n", &uint64Val, uint64(76)},
245 {"%b", "1001001\n", &uintVal, uint(73)},
246 {"%o", "075\n", &uintVal, uint(075)},
247 {"%x", "a75\n", &uintVal, uint(0xa75)},
248 {"%x", "A75\n", &uintVal, uint(0xa75)},
ff5f50c5
ILT
249 {"%U", "U+1234\n", &intVal, int(0x1234)},
250 {"%U", "U+4567\n", &uintVal, uint(0x4567)},
7a938933
ILT
251
252 // Strings
253 {"%s", "using-%s\n", &stringVal, "using-%s"},
254 {"%x", "7573696e672d2578\n", &stringVal, "using-%x"},
255 {"%q", `"quoted\twith\\do\u0075bl\x65s"` + "\n", &stringVal, "quoted\twith\\doubles"},
256 {"%q", "`quoted with backs`\n", &stringVal, "quoted with backs"},
257
258 // Byte slices
259 {"%s", "bytes-%s\n", &bytesVal, []byte("bytes-%s")},
260 {"%x", "62797465732d2578\n", &bytesVal, []byte("bytes-%x")},
261 {"%q", `"bytes\rwith\vdo\u0075bl\x65s"` + "\n", &bytesVal, []byte("bytes\rwith\vdoubles")},
262 {"%q", "`bytes with backs`\n", &bytesVal, []byte("bytes with backs")},
263
264 // Renamed types
265 {"%v\n", "true\n", &renamedBoolVal, renamedBool(true)},
266 {"%t\n", "F\n", &renamedBoolVal, renamedBool(false)},
267 {"%v", "101\n", &renamedIntVal, renamedInt(101)},
268 {"%c", "\u0101\n", &renamedIntVal, renamedInt('\u0101')},
269 {"%o", "0146\n", &renamedIntVal, renamedInt(102)},
270 {"%v", "103\n", &renamedUintVal, renamedUint(103)},
271 {"%d", "104\n", &renamedUintVal, renamedUint(104)},
272 {"%d", "105\n", &renamedInt8Val, renamedInt8(105)},
273 {"%d", "106\n", &renamedInt16Val, renamedInt16(106)},
274 {"%d", "107\n", &renamedInt32Val, renamedInt32(107)},
275 {"%d", "108\n", &renamedInt64Val, renamedInt64(108)},
276 {"%x", "6D\n", &renamedUint8Val, renamedUint8(109)},
277 {"%o", "0156\n", &renamedUint16Val, renamedUint16(110)},
278 {"%d", "111\n", &renamedUint32Val, renamedUint32(111)},
279 {"%d", "112\n", &renamedUint64Val, renamedUint64(112)},
280 {"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)},
281 {"%s", "114\n", &renamedStringVal, renamedString("114")},
282 {"%q", "\"1155\"\n", &renamedBytesVal, renamedBytes([]byte("1155"))},
7a938933
ILT
283 {"%g", "116e1\n", &renamedFloat32Val, renamedFloat32(116e1)},
284 {"%g", "-11.7e+1", &renamedFloat64Val, renamedFloat64(-11.7e+1)},
7a938933
ILT
285 {"%g", "11+6e1i\n", &renamedComplex64Val, renamedComplex64(11 + 6e1i)},
286 {"%g", "-11.+7e+1i", &renamedComplex128Val, renamedComplex128(-11. + 7e+1i)},
287
288 // Interesting formats
289 {"here is\tthe value:%d", "here is the\tvalue:118\n", &intVal, 118},
290 {"%% %%:%d", "% %:119\n", &intVal, 119},
291
292 // Corner cases
293 {"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
294
295 // Custom scanner.
296 {"%s", " sss ", &xVal, Xs("sss")},
297 {"%2s", "sssss", &xVal, Xs("ss")},
298
299 // Fixed bugs
300 {"%d\n", "27\n", &intVal, 27}, // ok
301 {"%d\n", "28 \n", &intVal, 28}, // was: "unexpected newline"
adb0401d
ILT
302 {"%v", "0", &intVal, 0}, // was: "EOF"; 0 was taken as base prefix and not counted.
303 {"%v", "0", &uintVal, uint(0)}, // was: "EOF"; 0 was taken as base prefix and not counted.
7a938933
ILT
304}
305
306var overflowTests = []ScanTest{
307 {"128", &int8Val, 0},
308 {"32768", &int16Val, 0},
309 {"-129", &int8Val, 0},
310 {"-32769", &int16Val, 0},
311 {"256", &uint8Val, 0},
312 {"65536", &uint16Val, 0},
313 {"1e100", &float32Val, 0},
314 {"1e500", &float64Val, 0},
ff5f50c5 315 {"(1e100+0i)", &complex64Val, 0},
7a938933
ILT
316 {"(1+1e100i)", &complex64Val, 0},
317 {"(1-1e500i)", &complex128Val, 0},
318}
319
cbb6491d 320var truth bool
7a938933 321var i, j, k int
ff5f50c5 322var f float64
7a938933 323var s, t string
ff5f50c5 324var c complex128
7a938933 325var x, y Xs
5133f00e 326var z IntString
9a0e3259 327var r1, r2, r3 rune
7a938933
ILT
328
329var multiTests = []ScanfMultiTest{
ab61e9c4 330 {"", "", []interface{}{}, []interface{}{}, ""},
7a938933
ILT
331 {"%d", "23", args(&i), args(23), ""},
332 {"%2s%3s", "22333", args(&s, &t), args("22", "333"), ""},
333 {"%2d%3d", "44555", args(&i, &j), args(44, 555), ""},
334 {"%2d.%3d", "66.777", args(&i, &j), args(66, 777), ""},
335 {"%d, %d", "23, 18", args(&i, &j), args(23, 18), ""},
336 {"%3d22%3d", "33322333", args(&i, &j), args(333, 333), ""},
ff5f50c5 337 {"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), 2.5), ""},
7a938933 338 {"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""},
9a0e3259 339 {"%c%c%c", "2\u50c2X", args(&r1, &r2, &r3), args('2', '\u50c2', 'X'), ""},
7a938933 340
5133f00e 341 // Custom scanners.
8039ca76 342 {"%e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
5133f00e 343 {"%4v%s", "12abcd", args(&z, &s), args(IntString{12, "ab"}, "cd"), ""},
7a938933
ILT
344
345 // Errors
346 {"%t", "23 18", args(&i), nil, "bad verb"},
347 {"%d %d %d", "23 18", args(&i, &j), args(23, 18), "too few operands"},
348 {"%d %d", "23 18 27", args(&i, &j, &k), args(23, 18), "too many operands"},
349 {"%c", "\u0100", args(&int8Val), nil, "overflow"},
350 {"X%d", "10X", args(&intVal), nil, "input does not match format"},
351
352 // Bad UTF-8: should see every byte.
9a0e3259 353 {"%c%c%c", "\xc2X\xc2", args(&r1, &r2, &r3), args(utf8.RuneError, 'X', utf8.RuneError), ""},
cbb6491d
ILT
354
355 // Fixed bugs
356 {"%v%v", "FALSE23", args(&truth, &i), args(false, 23), ""},
7a938933
ILT
357}
358
2fd401c8 359func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, error)) {
7a938933
ILT
360 for _, test := range scanTests {
361 var r io.Reader
362 if name == "StringReader" {
363 r = strings.NewReader(test.text)
364 } else {
365 r = newReader(test.text)
366 }
367 n, err := scan(r, test.in)
368 if err != nil {
5133f00e
ILT
369 m := ""
370 if n > 0 {
371 m = Sprintf(" (%d fields ok)", n)
372 }
373 t.Errorf("%s got error scanning %q: %s%s", name, test.text, err, m)
7a938933
ILT
374 continue
375 }
376 if n != 1 {
377 t.Errorf("%s count error on entry %q: got %d", name, test.text, n)
378 continue
379 }
380 // The incoming value may be a pointer
9ff56c95
ILT
381 v := reflect.ValueOf(test.in)
382 if p := v; p.Kind() == reflect.Ptr {
7a938933
ILT
383 v = p.Elem()
384 }
385 val := v.Interface()
386 if !reflect.DeepEqual(val, test.out) {
ab61e9c4 387 t.Errorf("%s scanning %q: expected %#v got %#v, type %T", name, test.text, test.out, val, val)
7a938933
ILT
388 }
389 }
390}
391
392func TestScan(t *testing.T) {
393 testScan("StringReader", t, Fscan)
394}
395
396func TestMyReaderScan(t *testing.T) {
397 testScan("myStringReader", t, Fscan)
398}
399
400func TestScanln(t *testing.T) {
401 testScan("StringReader", t, Fscanln)
402}
403
404func TestMyReaderScanln(t *testing.T) {
405 testScan("myStringReader", t, Fscanln)
406}
407
408func TestScanf(t *testing.T) {
409 for _, test := range scanfTests {
410 n, err := Sscanf(test.text, test.format, test.in)
411 if err != nil {
412 t.Errorf("got error scanning (%q, %q): %s", test.format, test.text, err)
413 continue
414 }
415 if n != 1 {
416 t.Errorf("count error on entry (%q, %q): got %d", test.format, test.text, n)
417 continue
418 }
419 // The incoming value may be a pointer
9ff56c95
ILT
420 v := reflect.ValueOf(test.in)
421 if p := v; p.Kind() == reflect.Ptr {
7a938933
ILT
422 v = p.Elem()
423 }
424 val := v.Interface()
425 if !reflect.DeepEqual(val, test.out) {
ab61e9c4 426 t.Errorf("scanning (%q, %q): expected %#v got %#v, type %T", test.format, test.text, test.out, val, val)
7a938933
ILT
427 }
428 }
429}
430
431func TestScanOverflow(t *testing.T) {
432 // different machines and different types report errors with different strings.
433 re := regexp.MustCompile("overflow|too large|out of range|not representable")
434 for _, test := range overflowTests {
435 _, err := Sscan(test.text, test.in)
436 if err == nil {
437 t.Errorf("expected overflow scanning %q", test.text)
438 continue
439 }
2fd401c8 440 if !re.MatchString(err.Error()) {
7a938933
ILT
441 t.Errorf("expected overflow error scanning %q: %s", test.text, err)
442 }
443 }
444}
445
ff5f50c5
ILT
446func verifyNaN(str string, t *testing.T) {
447 var f float64
448 var f32 float32
449 var f64 float64
450 text := str + " " + str + " " + str
451 n, err := Fscan(strings.NewReader(text), &f, &f32, &f64)
452 if err != nil {
453 t.Errorf("got error scanning %q: %s", text, err)
454 }
455 if n != 3 {
456 t.Errorf("count error scanning %q: got %d", text, n)
457 }
458 if !math.IsNaN(float64(f)) || !math.IsNaN(float64(f32)) || !math.IsNaN(f64) {
459 t.Errorf("didn't get NaNs scanning %q: got %g %g %g", text, f, f32, f64)
460 }
461}
462
463func TestNaN(t *testing.T) {
464 for _, s := range []string{"nan", "NAN", "NaN"} {
465 verifyNaN(s, t)
466 }
467}
468
469func verifyInf(str string, t *testing.T) {
470 var f float64
471 var f32 float32
472 var f64 float64
473 text := str + " " + str + " " + str
474 n, err := Fscan(strings.NewReader(text), &f, &f32, &f64)
475 if err != nil {
476 t.Errorf("got error scanning %q: %s", text, err)
477 }
478 if n != 3 {
479 t.Errorf("count error scanning %q: got %d", text, n)
480 }
481 sign := 1
482 if str[0] == '-' {
483 sign = -1
484 }
485 if !math.IsInf(float64(f), sign) || !math.IsInf(float64(f32), sign) || !math.IsInf(f64, sign) {
486 t.Errorf("didn't get right Infs scanning %q: got %g %g %g", text, f, f32, f64)
487 }
488}
489
ff5f50c5
ILT
490func TestInf(t *testing.T) {
491 for _, s := range []string{"inf", "+inf", "-inf", "INF", "-INF", "+INF", "Inf", "-Inf", "+Inf"} {
492 verifyInf(s, t)
493 }
494}
495
7a938933 496func testScanfMulti(name string, t *testing.T) {
9ff56c95 497 sliceType := reflect.TypeOf(make([]interface{}, 1))
7a938933
ILT
498 for _, test := range multiTests {
499 var r io.Reader
500 if name == "StringReader" {
501 r = strings.NewReader(test.text)
502 } else {
503 r = newReader(test.text)
504 }
8039ca76 505 n, err := Fscanf(r, test.format, test.in...)
7a938933
ILT
506 if err != nil {
507 if test.err == "" {
508 t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
2fd401c8 509 } else if strings.Index(err.Error(), test.err) < 0 {
7a938933
ILT
510 t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err)
511 }
512 continue
513 }
514 if test.err != "" {
515 t.Errorf("expected error %q error scanning (%q, %q)", test.err, test.format, test.text)
516 }
517 if n != len(test.out) {
518 t.Errorf("count error on entry (%q, %q): expected %d got %d", test.format, test.text, len(test.out), n)
519 continue
520 }
521 // Convert the slice of pointers into a slice of values
522 resultVal := reflect.MakeSlice(sliceType, n, n)
523 for i := 0; i < n; i++ {
9ff56c95
ILT
524 v := reflect.ValueOf(test.in[i]).Elem()
525 resultVal.Index(i).Set(v)
7a938933
ILT
526 }
527 result := resultVal.Interface()
528 if !reflect.DeepEqual(result, test.out) {
ab61e9c4 529 t.Errorf("scanning (%q, %q): expected %#v got %#v", test.format, test.text, test.out, result)
7a938933
ILT
530 }
531 }
532}
533
534func TestScanfMulti(t *testing.T) {
535 testScanfMulti("StringReader", t)
536}
537
538func TestMyReaderScanfMulti(t *testing.T) {
539 testScanfMulti("myStringReader", t)
540}
541
542func TestScanMultiple(t *testing.T) {
543 var a int
544 var s string
545 n, err := Sscan("123abc", &a, &s)
546 if n != 2 {
547 t.Errorf("Sscan count error: expected 2: got %d", n)
548 }
549 if err != nil {
550 t.Errorf("Sscan expected no error; got %s", err)
551 }
552 if a != 123 || s != "abc" {
553 t.Errorf("Sscan wrong values: got (%d %q) expected (123 \"abc\")", a, s)
554 }
555 n, err = Sscan("asdf", &s, &a)
556 if n != 1 {
557 t.Errorf("Sscan count error: expected 1: got %d", n)
558 }
559 if err == nil {
ff5f50c5 560 t.Errorf("Sscan expected error; got none: %s", err)
7a938933
ILT
561 }
562 if s != "asdf" {
563 t.Errorf("Sscan wrong values: got %q expected \"asdf\"", s)
564 }
565}
566
567// Empty strings are not valid input when scanning a string.
568func TestScanEmpty(t *testing.T) {
569 var s1, s2 string
570 n, err := Sscan("abc", &s1, &s2)
571 if n != 1 {
572 t.Errorf("Sscan count error: expected 1: got %d", n)
573 }
574 if err == nil {
ff5f50c5 575 t.Error("Sscan <one item> expected error; got none")
7a938933
ILT
576 }
577 if s1 != "abc" {
578 t.Errorf("Sscan wrong values: got %q expected \"abc\"", s1)
579 }
580 n, err = Sscan("", &s1, &s2)
581 if n != 0 {
582 t.Errorf("Sscan count error: expected 0: got %d", n)
583 }
584 if err == nil {
ff5f50c5 585 t.Error("Sscan <empty> expected error; got none")
7a938933
ILT
586 }
587 // Quoted empty string is OK.
588 n, err = Sscanf(`""`, "%q", &s1)
589 if n != 1 {
590 t.Errorf("Sscanf count error: expected 1: got %d", n)
591 }
592 if err != nil {
593 t.Errorf("Sscanf <empty> expected no error with quoted string; got %s", err)
594 }
595}
596
597func TestScanNotPointer(t *testing.T) {
598 r := strings.NewReader("1")
599 var a int
600 _, err := Fscan(r, a)
601 if err == nil {
602 t.Error("expected error scanning non-pointer")
2fd401c8 603 } else if strings.Index(err.Error(), "pointer") < 0 {
7a938933
ILT
604 t.Errorf("expected pointer error scanning non-pointer, got: %s", err)
605 }
606}
607
608func TestScanlnNoNewline(t *testing.T) {
609 var a int
610 _, err := Sscanln("1 x\n", &a)
611 if err == nil {
612 t.Error("expected error scanning string missing newline")
2fd401c8 613 } else if strings.Index(err.Error(), "newline") < 0 {
7a938933
ILT
614 t.Errorf("expected newline error scanning string missing newline, got: %s", err)
615 }
616}
617
618func TestScanlnWithMiddleNewline(t *testing.T) {
619 r := strings.NewReader("123\n456\n")
620 var a, b int
621 _, err := Fscanln(r, &a, &b)
622 if err == nil {
623 t.Error("expected error scanning string with extra newline")
2fd401c8 624 } else if strings.Index(err.Error(), "newline") < 0 {
7a938933
ILT
625 t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
626 }
627}
628
629// Special Reader that counts reads at end of file.
630type eofCounter struct {
631 reader *strings.Reader
632 eofCount int
633}
634
2fd401c8 635func (ec *eofCounter) Read(b []byte) (n int, err error) {
7a938933
ILT
636 n, err = ec.reader.Read(b)
637 if n == 0 {
638 ec.eofCount++
639 }
640 return
641}
642
643// Verify that when we scan, we see at most EOF once per call to a Scan function,
644// and then only when it's really an EOF
645func TestEOF(t *testing.T) {
646 ec := &eofCounter{strings.NewReader("123\n"), 0}
647 var a int
648 n, err := Fscanln(ec, &a)
649 if err != nil {
650 t.Error("unexpected error", err)
651 }
652 if n != 1 {
653 t.Error("expected to scan one item, got", n)
654 }
655 if ec.eofCount != 0 {
656 t.Error("expected zero EOFs", ec.eofCount)
657 ec.eofCount = 0 // reset for next test
658 }
659 n, err = Fscanln(ec, &a)
660 if err == nil {
661 t.Error("expected error scanning empty string")
662 }
663 if n != 0 {
664 t.Error("expected to scan zero items, got", n)
665 }
666 if ec.eofCount != 1 {
667 t.Error("expected one EOF, got", ec.eofCount)
668 }
669}
670
adb0401d
ILT
671// Verify that we see an EOF error if we run out of input.
672// This was a buglet: we used to get "expected integer".
673func TestEOFAtEndOfInput(t *testing.T) {
674 var i, j int
675 n, err := Sscanf("23", "%d %d", &i, &j)
676 if n != 1 || i != 23 {
677 t.Errorf("Sscanf expected one value of 23; got %d %d", n, i)
678 }
2fd401c8 679 if err != io.EOF {
adb0401d
ILT
680 t.Errorf("Sscanf expected EOF; got %q", err)
681 }
682 n, err = Sscan("234", &i, &j)
683 if n != 1 || i != 234 {
684 t.Errorf("Sscan expected one value of 234; got %d %d", n, i)
685 }
2fd401c8 686 if err != io.EOF {
adb0401d
ILT
687 t.Errorf("Sscan expected EOF; got %q", err)
688 }
689 // Trailing space is tougher.
690 n, err = Sscan("234 ", &i, &j)
691 if n != 1 || i != 234 {
692 t.Errorf("Sscan expected one value of 234; got %d %d", n, i)
693 }
2fd401c8 694 if err != io.EOF {
adb0401d
ILT
695 t.Errorf("Sscan expected EOF; got %q", err)
696 }
697}
698
699var eofTests = []struct {
700 format string
701 v interface{}
702}{
703 {"%s", &stringVal},
704 {"%q", &stringVal},
705 {"%x", &stringVal},
706 {"%v", &stringVal},
707 {"%v", &bytesVal},
708 {"%v", &intVal},
709 {"%v", &uintVal},
710 {"%v", &boolVal},
711 {"%v", &float32Val},
712 {"%v", &complex64Val},
713 {"%v", &renamedStringVal},
714 {"%v", &renamedBytesVal},
715 {"%v", &renamedIntVal},
716 {"%v", &renamedUintVal},
717 {"%v", &renamedBoolVal},
718 {"%v", &renamedFloat32Val},
719 {"%v", &renamedComplex64Val},
720}
721
722func TestEOFAllTypes(t *testing.T) {
723 for i, test := range eofTests {
2fd401c8 724 if _, err := Sscanf("", test.format, test.v); err != io.EOF {
adb0401d
ILT
725 t.Errorf("#%d: %s %T not eof on empty string: %s", i, test.format, test.v, err)
726 }
2fd401c8 727 if _, err := Sscanf(" ", test.format, test.v); err != io.EOF {
adb0401d
ILT
728 t.Errorf("#%d: %s %T not eof on trailing blanks: %s", i, test.format, test.v, err)
729 }
730 }
731}
732
7a938933
ILT
733// Verify that, at least when using bufio, successive calls to Fscan do not lose runes.
734func TestUnreadRuneWithBufio(t *testing.T) {
735 r := bufio.NewReader(strings.NewReader("123αb"))
736 var i int
737 var a string
738 n, err := Fscanf(r, "%d", &i)
739 if n != 1 || err != nil {
740 t.Errorf("reading int expected one item, no errors; got %d %q", n, err)
741 }
742 if i != 123 {
743 t.Errorf("expected 123; got %d", i)
744 }
745 n, err = Fscanf(r, "%s", &a)
746 if n != 1 || err != nil {
747 t.Errorf("reading string expected one item, no errors; got %d %q", n, err)
748 }
749 if a != "αb" {
750 t.Errorf("expected αb; got %q", a)
751 }
752}
5133f00e
ILT
753
754type TwoLines string
755
756// Attempt to read two lines into the object. Scanln should prevent this
757// because it stops at newline; Scan and Scanf should be fine.
2fd401c8 758func (t *TwoLines) Scan(state ScanState, verb rune) error {
506cf9aa 759 chars := make([]rune, 0, 100)
5133f00e
ILT
760 for nlCount := 0; nlCount < 2; {
761 c, _, err := state.ReadRune()
762 if err != nil {
763 return err
764 }
765 chars = append(chars, c)
766 if c == '\n' {
767 nlCount++
768 }
769 }
770 *t = TwoLines(string(chars))
771 return nil
772}
773
774func TestMultiLine(t *testing.T) {
775 input := "abc\ndef\n"
776 // Sscan should work
777 var tscan TwoLines
778 n, err := Sscan(input, &tscan)
779 if n != 1 {
780 t.Errorf("Sscan: expected 1 item; got %d", n)
781 }
782 if err != nil {
783 t.Errorf("Sscan: expected no error; got %s", err)
784 }
785 if string(tscan) != input {
786 t.Errorf("Sscan: expected %q; got %q", input, tscan)
787 }
788 // Sscanf should work
789 var tscanf TwoLines
790 n, err = Sscanf(input, "%s", &tscanf)
791 if n != 1 {
792 t.Errorf("Sscanf: expected 1 item; got %d", n)
793 }
794 if err != nil {
795 t.Errorf("Sscanf: expected no error; got %s", err)
796 }
797 if string(tscanf) != input {
798 t.Errorf("Sscanf: expected %q; got %q", input, tscanf)
799 }
800 // Sscanln should not work
801 var tscanln TwoLines
802 n, err = Sscanln(input, &tscanln)
803 if n != 0 {
804 t.Errorf("Sscanln: expected 0 items; got %d: %q", n, tscanln)
805 }
806 if err == nil {
807 t.Error("Sscanln: expected error; got none")
808 } else if err != io.ErrUnexpectedEOF {
809 t.Errorf("Sscanln: expected io.ErrUnexpectedEOF (ha!); got %s", err)
810 }
811}
812
4ccad563
ILT
813// simpleReader is a strings.Reader that implements only Read, not ReadRune.
814// Good for testing readahead.
815type simpleReader struct {
816 sr *strings.Reader
817}
818
819func (s *simpleReader) Read(b []byte) (n int, err error) {
820 return s.sr.Read(b)
821}
822
823// Test that Fscanf does not read past newline. Issue 3481.
824func TestLineByLineFscanf(t *testing.T) {
825 r := &simpleReader{strings.NewReader("1\n2\n")}
826 var i, j int
827 n, err := Fscanf(r, "%v\n", &i)
828 if n != 1 || err != nil {
829 t.Fatalf("first read: %d %q", n, err)
830 }
831 n, err = Fscanf(r, "%v\n", &j)
832 if n != 1 || err != nil {
833 t.Fatalf("second read: %d %q", n, err)
834 }
835 if i != 1 || j != 2 {
836 t.Errorf("wrong values; wanted 1 2 got %d %d", i, j)
837 }
838}
839
9a18821c 840// RecursiveInt accepts a string matching %d.%d.%d....
5133f00e
ILT
841// and parses it into a linked list.
842// It allows us to benchmark recursive descent style scanners.
843type RecursiveInt struct {
844 i int
845 next *RecursiveInt
846}
847
2fd401c8 848func (r *RecursiveInt) Scan(state ScanState, verb rune) (err error) {
5133f00e
ILT
849 _, err = Fscan(state, &r.i)
850 if err != nil {
851 return
852 }
853 next := new(RecursiveInt)
854 _, err = Fscanf(state, ".%v", next)
855 if err != nil {
9a18821c 856 if err == io.ErrUnexpectedEOF {
5133f00e
ILT
857 err = nil
858 }
859 return
860 }
861 r.next = next
862 return
863}
864
865// Perform the same scanning task as RecursiveInt.Scan
866// but without recurring through scanner, so we can compare
867// performance more directly.
2fd401c8 868func scanInts(r *RecursiveInt, b *bytes.Buffer) (err error) {
5133f00e
ILT
869 r.next = nil
870 _, err = Fscan(b, &r.i)
871 if err != nil {
872 return
873 }
506cf9aa 874 c, _, err := b.ReadRune()
5133f00e 875 if err != nil {
2fd401c8 876 if err == io.EOF {
5133f00e
ILT
877 err = nil
878 }
879 return
880 }
881 if c != '.' {
882 return
883 }
884 next := new(RecursiveInt)
885 err = scanInts(next, b)
886 if err == nil {
887 r.next = next
888 }
889 return
890}
891
892func makeInts(n int) []byte {
893 var buf bytes.Buffer
894 Fprintf(&buf, "1")
895 for i := 1; i < n; i++ {
896 Fprintf(&buf, ".%d", i+1)
897 }
898 return buf.Bytes()
899}
900
901func TestScanInts(t *testing.T) {
902 testScanInts(t, scanInts)
2fd401c8 903 testScanInts(t, func(r *RecursiveInt, b *bytes.Buffer) (err error) {
5133f00e
ILT
904 _, err = Fscan(b, r)
905 return
906 })
907}
908
549dd8fe
ILT
909// 800 is small enough to not overflow the stack when using gccgo on a
910// platform that does not support split stack.
911const intCount = 800
5133f00e 912
2fd401c8 913func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) error) {
5133f00e
ILT
914 r := new(RecursiveInt)
915 ints := makeInts(intCount)
916 buf := bytes.NewBuffer(ints)
917 err := scan(r, buf)
918 if err != nil {
919 t.Error("unexpected error", err)
920 }
921 i := 1
922 for ; r != nil; r = r.next {
923 if r.i != i {
8039ca76 924 t.Fatalf("bad scan: expected %d got %d", i, r.i)
5133f00e
ILT
925 }
926 i++
927 }
928 if i-1 != intCount {
8039ca76 929 t.Fatalf("bad scan count: expected %d got %d", intCount, i-1)
5133f00e
ILT
930 }
931}
932
933func BenchmarkScanInts(b *testing.B) {
934 b.ResetTimer()
935 ints := makeInts(intCount)
936 var r RecursiveInt
937 for i := b.N - 1; i >= 0; i-- {
938 buf := bytes.NewBuffer(ints)
939 b.StartTimer()
940 scanInts(&r, buf)
941 b.StopTimer()
942 }
943}
944
945func BenchmarkScanRecursiveInt(b *testing.B) {
946 b.ResetTimer()
947 ints := makeInts(intCount)
948 var r RecursiveInt
949 for i := b.N - 1; i >= 0; i-- {
950 buf := bytes.NewBuffer(ints)
951 b.StartTimer()
952 Fscan(buf, &r)
953 b.StopTimer()
954 }
955}