summaryrefslogtreecommitdiff
path: root/src/pkg/bytes
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2014-06-19 09:22:53 +0200
committerMichael Stapelberg <stapelberg@debian.org>2014-06-19 09:22:53 +0200
commit8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 (patch)
tree4449f2036cccf162e8417cc5841a35815b3e7ac5 /src/pkg/bytes
parentc8bf49ef8a92e2337b69c14b9b88396efe498600 (diff)
downloadgolang-upstream/1.3.tar.gz
Imported Upstream version 1.3upstream/1.3
Diffstat (limited to 'src/pkg/bytes')
-rw-r--r--src/pkg/bytes/bytes.go10
-rw-r--r--src/pkg/bytes/bytes_test.go36
-rw-r--r--src/pkg/bytes/compare_test.go4
-rw-r--r--src/pkg/bytes/reader.go52
-rw-r--r--src/pkg/bytes/reader_test.go82
5 files changed, 148 insertions, 36 deletions
diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go
index 01a5d9ae4..0c53e4c0b 100644
--- a/src/pkg/bytes/bytes.go
+++ b/src/pkg/bytes/bytes.go
@@ -265,8 +265,8 @@ func Fields(s []byte) [][]byte {
// FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
// It splits the slice s at each run of code points c satisfying f(c) and
-// returns a slice of subslices of s. If no code points in s satisfy f(c), an
-// empty slice is returned.
+// returns a slice of subslices of s. If all code points in s satisfy f(c), or
+// len(s) == 0, an empty slice is returned.
func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
n := 0
inField := false
@@ -356,7 +356,11 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
}
r = mapping(r)
if r >= 0 {
- if nbytes+utf8.RuneLen(r) > maxbytes {
+ rl := utf8.RuneLen(r)
+ if rl < 0 {
+ rl = len(string(utf8.RuneError))
+ }
+ if nbytes+rl > maxbytes {
// Grow the buffer.
maxbytes = maxbytes*2 + utf8.UTFMax
nb := make([]byte, maxbytes)
diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go
index ab5da4fbf..394dd7a44 100644
--- a/src/pkg/bytes/bytes_test.go
+++ b/src/pkg/bytes/bytes_test.go
@@ -785,6 +785,16 @@ func TestMap(t *testing.T) {
if string(m) != expect {
t.Errorf("drop: expected %q got %q", expect, m)
}
+
+ // 6. Invalid rune
+ invalidRune := func(r rune) rune {
+ return utf8.MaxRune + 1
+ }
+ m = Map(invalidRune, []byte("x"))
+ expect = "\uFFFD"
+ if string(m) != expect {
+ t.Errorf("invalidRune: expected %q got %q", expect, m)
+ }
}
func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
@@ -1073,6 +1083,8 @@ var TitleTests = []TitleTest{
{"123a456", "123a456"},
{"double-blind", "Double-Blind"},
{"ÿøû", "Ÿøû"},
+ {"with_underscore", "With_underscore"},
+ {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"},
}
func TestTitle(t *testing.T) {
@@ -1132,7 +1144,7 @@ func TestEqualFold(t *testing.T) {
func TestBufferGrowNegative(t *testing.T) {
defer func() {
if err := recover(); err == nil {
- t.Fatal("Grow(-1) should have paniced")
+ t.Fatal("Grow(-1) should have panicked")
}
}()
var b Buffer
@@ -1142,7 +1154,7 @@ func TestBufferGrowNegative(t *testing.T) {
func TestBufferTruncateNegative(t *testing.T) {
defer func() {
if err := recover(); err == nil {
- t.Fatal("Truncate(-1) should have paniced")
+ t.Fatal("Truncate(-1) should have panicked")
}
}()
var b Buffer
@@ -1152,7 +1164,7 @@ func TestBufferTruncateNegative(t *testing.T) {
func TestBufferTruncateOutOfRange(t *testing.T) {
defer func() {
if err := recover(); err == nil {
- t.Fatal("Truncate(20) should have paniced")
+ t.Fatal("Truncate(20) should have panicked")
}
}()
var b Buffer
@@ -1160,6 +1172,24 @@ func TestBufferTruncateOutOfRange(t *testing.T) {
b.Truncate(20)
}
+var containsTests = []struct {
+ b, subslice []byte
+ want bool
+}{
+ {[]byte("hello"), []byte("hel"), true},
+ {[]byte("日本語"), []byte("日本"), true},
+ {[]byte("hello"), []byte("Hello, world"), false},
+ {[]byte("東京"), []byte("京東"), false},
+}
+
+func TestContains(t *testing.T) {
+ for _, tt := range containsTests {
+ if got := Contains(tt.b, tt.subslice); got != tt.want {
+ t.Errorf("Contains(%q, %q) = %v, want %v", tt.b, tt.subslice, got, tt.want)
+ }
+ }
+}
+
var makeFieldsInput = func() []byte {
x := make([]byte, 1<<20)
// Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space.
diff --git a/src/pkg/bytes/compare_test.go b/src/pkg/bytes/compare_test.go
index 0a36f5ad3..63522374e 100644
--- a/src/pkg/bytes/compare_test.go
+++ b/src/pkg/bytes/compare_test.go
@@ -1,3 +1,7 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package bytes_test
import (
diff --git a/src/pkg/bytes/reader.go b/src/pkg/bytes/reader.go
index 77511b945..d2d40fa7c 100644
--- a/src/pkg/bytes/reader.go
+++ b/src/pkg/bytes/reader.go
@@ -16,40 +16,41 @@ import (
// Unlike a Buffer, a Reader is read-only and supports seeking.
type Reader struct {
s []byte
- i int // current reading index
- prevRune int // index of previous rune; or < 0
+ i int64 // current reading index
+ prevRune int // index of previous rune; or < 0
}
// Len returns the number of bytes of the unread portion of the
// slice.
func (r *Reader) Len() int {
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0
}
- return len(r.s) - r.i
+ return int(int64(len(r.s)) - r.i)
}
func (r *Reader) Read(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
- n = copy(b, r.s[r.i:])
- r.i += n
r.prevRune = -1
+ n = copy(b, r.s[r.i:])
+ r.i += int64(n)
return
}
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
+ // cannot modify state - see io.ReaderAt
if off < 0 {
- return 0, errors.New("bytes: invalid offset")
+ return 0, errors.New("bytes.Reader.ReadAt: negative offset")
}
if off >= int64(len(r.s)) {
return 0, io.EOF
}
- n = copy(b, r.s[int(off):])
+ n = copy(b, r.s[off:])
if n < len(b) {
err = io.EOF
}
@@ -57,49 +58,51 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
}
func (r *Reader) ReadByte() (b byte, err error) {
- if r.i >= len(r.s) {
+ r.prevRune = -1
+ if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
b = r.s[r.i]
r.i++
- r.prevRune = -1
return
}
func (r *Reader) UnreadByte() error {
+ r.prevRune = -1
if r.i <= 0 {
- return errors.New("bytes.Reader: at beginning of slice")
+ return errors.New("bytes.Reader.UnreadByte: at beginning of slice")
}
r.i--
- r.prevRune = -1
return nil
}
func (r *Reader) ReadRune() (ch rune, size int, err error) {
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
+ r.prevRune = -1
return 0, 0, io.EOF
}
- r.prevRune = r.i
+ r.prevRune = int(r.i)
if c := r.s[r.i]; c < utf8.RuneSelf {
r.i++
return rune(c), 1, nil
}
ch, size = utf8.DecodeRune(r.s[r.i:])
- r.i += size
+ r.i += int64(size)
return
}
func (r *Reader) UnreadRune() error {
if r.prevRune < 0 {
- return errors.New("bytes.Reader: previous operation was not ReadRune")
+ return errors.New("bytes.Reader.UnreadRune: previous operation was not ReadRune")
}
- r.i = r.prevRune
+ r.i = int64(r.prevRune)
r.prevRune = -1
return nil
}
// Seek implements the io.Seeker interface.
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
+ r.prevRune = -1
var abs int64
switch whence {
case 0:
@@ -109,22 +112,19 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
case 2:
abs = int64(len(r.s)) + offset
default:
- return 0, errors.New("bytes: invalid whence")
+ return 0, errors.New("bytes.Reader.Seek: invalid whence")
}
if abs < 0 {
- return 0, errors.New("bytes: negative position")
- }
- if abs >= 1<<31 {
- return 0, errors.New("bytes: position out of range")
+ return 0, errors.New("bytes.Reader.Seek: negative position")
}
- r.i = int(abs)
+ r.i = abs
return abs, nil
}
// WriteTo implements the io.WriterTo interface.
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1
- if r.i >= len(r.s) {
+ if r.i >= int64(len(r.s)) {
return 0, nil
}
b := r.s[r.i:]
@@ -132,7 +132,7 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
if m > len(b) {
panic("bytes.Reader.WriteTo: invalid Write count")
}
- r.i += m
+ r.i += int64(m)
n = int64(m)
if m != len(b) && err == nil {
err = io.ErrShortWrite
diff --git a/src/pkg/bytes/reader_test.go b/src/pkg/bytes/reader_test.go
index 19f014da0..d3dce5349 100644
--- a/src/pkg/bytes/reader_test.go
+++ b/src/pkg/bytes/reader_test.go
@@ -10,6 +10,7 @@ import (
"io"
"io/ioutil"
"os"
+ "sync"
"testing"
)
@@ -26,9 +27,9 @@ func TestReader(t *testing.T) {
{seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
{seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
{seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
- {seek: os.SEEK_SET, off: -1, seekerr: "bytes: negative position"},
- {seek: os.SEEK_SET, off: 1<<31 - 1},
- {seek: os.SEEK_CUR, off: 1, seekerr: "bytes: position out of range"},
+ {seek: os.SEEK_SET, off: -1, seekerr: "bytes.Reader.Seek: negative position"},
+ {seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
+ {seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
{seek: os.SEEK_SET, n: 5, want: "01234"},
{seek: os.SEEK_CUR, n: 5, want: "56789"},
{seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
@@ -60,6 +61,16 @@ func TestReader(t *testing.T) {
}
}
+func TestReadAfterBigSeek(t *testing.T) {
+ r := NewReader([]byte("0123456789"))
+ if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+ t.Fatal(err)
+ }
+ if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
+ t.Errorf("Read = %d, %v; want 0, EOF", n, err)
+ }
+}
+
func TestReaderAt(t *testing.T) {
r := NewReader([]byte("0123456789"))
tests := []struct {
@@ -73,7 +84,7 @@ func TestReaderAt(t *testing.T) {
{1, 9, "123456789", nil},
{11, 10, "", io.EOF},
{0, 0, "", nil},
- {-1, 0, "", "bytes: invalid offset"},
+ {-1, 0, "", "bytes.Reader.ReadAt: negative offset"},
}
for i, tt := range tests {
b := make([]byte, tt.n)
@@ -88,6 +99,43 @@ func TestReaderAt(t *testing.T) {
}
}
+func TestReaderAtConcurrent(t *testing.T) {
+ // Test for the race detector, to verify ReadAt doesn't mutate
+ // any state.
+ r := NewReader([]byte("0123456789"))
+ var wg sync.WaitGroup
+ for i := 0; i < 5; i++ {
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+ var buf [1]byte
+ r.ReadAt(buf[:], int64(i))
+ }(i)
+ }
+ wg.Wait()
+}
+
+func TestEmptyReaderConcurrent(t *testing.T) {
+ // Test for the race detector, to verify a Read that doesn't yield any bytes
+ // is okay to use from multiple goroutines. This was our historic behavior.
+ // See golang.org/issue/7856
+ r := NewReader([]byte{})
+ var wg sync.WaitGroup
+ for i := 0; i < 5; i++ {
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ var buf [1]byte
+ r.Read(buf[:])
+ }()
+ go func() {
+ defer wg.Done()
+ r.Read(nil)
+ }()
+ }
+ wg.Wait()
+}
+
func TestReaderWriteTo(t *testing.T) {
for i := 0; i < 30; i += 3 {
var l int
@@ -133,6 +181,32 @@ func TestReaderLen(t *testing.T) {
}
}
+var UnreadRuneErrorTests = []struct {
+ name string
+ f func(*Reader)
+}{
+ {"Read", func(r *Reader) { r.Read([]byte{0}) }},
+ {"ReadByte", func(r *Reader) { r.ReadByte() }},
+ {"UnreadRune", func(r *Reader) { r.UnreadRune() }},
+ {"Seek", func(r *Reader) { r.Seek(0, 1) }},
+ {"WriteTo", func(r *Reader) { r.WriteTo(&Buffer{}) }},
+}
+
+func TestUnreadRuneError(t *testing.T) {
+ for _, tt := range UnreadRuneErrorTests {
+ reader := NewReader([]byte("0123456789"))
+ if _, _, err := reader.ReadRune(); err != nil {
+ // should not happen
+ t.Fatal(err)
+ }
+ tt.f(reader)
+ err := reader.UnreadRune()
+ if err == nil {
+ t.Errorf("Unreading after %s: expected error", tt.name)
+ }
+ }
+}
+
func TestReaderDoubleUnreadRune(t *testing.T) {
buf := NewBuffer([]byte("groucho"))
if _, _, err := buf.ReadRune(); err != nil {