diff --git a/charset.go b/charset.go index 9048745..e5ab744 100644 --- a/charset.go +++ b/charset.go @@ -21,7 +21,8 @@ func (u UnknownCharsetError) Error() string { // IsUnknownCharset returns a boolean indicating whether the error is known to // report that the charset advertised by the entity is unknown. func IsUnknownCharset(err error) bool { - return errors.As(err, new(UnknownCharsetError)) + _, ok := errors.AsType[UnknownCharsetError](err) + return ok } // CharsetReader, if non-nil, defines a function to generate charset-conversion diff --git a/charset/charset.go b/charset/charset.go index e37e1df..117d3cb 100644 --- a/charset/charset.go +++ b/charset/charset.go @@ -49,7 +49,7 @@ func charsetEncoding(charset string) (encoding.Encoding, error) { enc, err = htmlindex.Get(charset) } if err != nil { - return nil, fmt.Errorf("charset %q: %v", charset, err) + return nil, fmt.Errorf("charset %q: %w", charset, err) } // See https://github.com/golang/go/issues/19421 if enc == nil { diff --git a/charset/charset_test.go b/charset/charset_test.go index 93f1765..d82fd7b 100644 --- a/charset/charset_test.go +++ b/charset/charset_test.go @@ -2,10 +2,13 @@ package charset import ( "bytes" + "errors" "io" - "io/ioutil" + "strings" "testing" + + "golang.org/x/text/encoding/htmlindex" ) var testCharsets = []struct { @@ -70,7 +73,7 @@ func TestCharsetReader(t *testing.T) { if test.decoded != "" { if err != nil { t.Errorf("Expected no error when creating reader for charset %q, but got: %v", test.charset, err) - } else if b, err := ioutil.ReadAll(r); err != nil { + } else if b, err := io.ReadAll(r); err != nil { t.Errorf("Expected no error when reading charset %q, but got: %v", test.charset, err) } else if s := string(b); s != test.decoded { t.Errorf("Expected decoded text to be %q but got %q", test.decoded, s) @@ -121,3 +124,16 @@ func TestDisabledCharsetWriter(t *testing.T) { t.Errorf("Writer(): expected disabled charset to return an error") } } + +func TestUnknownCharsetWrapsCause(t *testing.T) { + const name = "no-such-charset" + _, want := htmlindex.Get(name) + if want == nil { + t.Fatalf("htmlindex.Get(%q): expected an error", name) + } + + _, err := charsetEncoding(name) + if !errors.Is(err, want) { + t.Errorf("charsetEncoding(%q) = %v, want an error wrapping %v", name, err, want) + } +} diff --git a/encoding.go b/encoding.go index 8f98c90..37fe30c 100644 --- a/encoding.go +++ b/encoding.go @@ -24,7 +24,8 @@ func (u UnknownEncodingError) Error() string { // IsUnknownEncoding returns a boolean indicating whether the error is known to // report that the encoding advertised by the entity is unknown. func IsUnknownEncoding(err error) bool { - return errors.As(err, new(UnknownEncodingError)) + _, ok := errors.AsType[UnknownEncodingError](err) + return ok } func encodingReader(enc string, r io.Reader) (io.Reader, error) { @@ -78,7 +79,7 @@ type whitespaceReplacingReader struct { func (r *whitespaceReplacingReader) Read(p []byte) (int, error) { n, err := r.wrapped.Read(p) - for i := 0; i < n; i++ { + for i := range n { if p[i] == ' ' || p[i] == '\t' { p[i] = '\n' } @@ -101,8 +102,7 @@ func (w *lineWrapper) Write(b []byte) (int, error) { var l []byte l, b = cutLine(b, w.maxLineLen-w.curLineLen) - lf := bytes.HasSuffix(l, []byte("\n")) - l = bytes.TrimSuffix(l, []byte("\n")) + l, lf := bytes.CutSuffix(l, []byte("\n")) n, err := w.w.Write(l) if err != nil { @@ -141,7 +141,7 @@ func (w *lineWrapper) Write(b []byte) (int, error) { } func cutLine(b []byte, max int) ([]byte, []byte) { - for i := 0; i < len(b); i++ { + for i := range b { if b[i] == '\r' && i == max { continue } diff --git a/encoding_test.go b/encoding_test.go index 153147f..c17ee51 100644 --- a/encoding_test.go +++ b/encoding_test.go @@ -3,7 +3,7 @@ package message import ( "bytes" "io" - "io/ioutil" + "strings" "testing" ) @@ -45,7 +45,7 @@ func TestDecode(t *testing.T) { r, err := encodingReader(test.enc, strings.NewReader(test.encoded)) if err != nil { t.Errorf("Expected no error when creating decoder for encoding %q, but got: %v", test.enc, err) - } else if b, err := ioutil.ReadAll(r); err != nil { + } else if b, err := io.ReadAll(r); err != nil { t.Errorf("Expected no error when reading encoding %q, but got: %v", test.enc, err) } else if s := string(b); s != test.decoded { t.Errorf("Expected decoded text to be %q but got %q", test.decoded, s) diff --git a/entity_test.go b/entity_test.go index f550ad5..30d86af 100644 --- a/entity_test.go +++ b/entity_test.go @@ -5,7 +5,6 @@ import ( "errors" "golang.org/x/text/encoding/ianaindex" "io" - "io/ioutil" "math" "reflect" "strings" @@ -27,7 +26,7 @@ func TestNewEntity(t *testing.T) { e := testMakeEntity() expected := "cc sava" - if b, err := ioutil.ReadAll(e.Body); err != nil { + if b, err := io.ReadAll(e.Body); err != nil { t.Error("Expected no error while reading entity body, got", err) } else if s := string(b); s != expected { t.Errorf("Expected %q as entity body but got %q", expected, s) @@ -129,7 +128,7 @@ func testMultipart(t *testing.T, e *Entity) { if mediaType := p.Header.Get("Content-Type"); mediaType != expectedType { t.Errorf("Expected part Content-Type to be %q, got %q", expectedType, mediaType) } - if b, err := ioutil.ReadAll(p.Body); err != nil { + if b, err := io.ReadAll(p.Body); err != nil { t.Error("Expected no error while reading part body, got", err) } else if s := string(b); s != expectedBody { t.Errorf("Expected %q as part body but got %q", expectedBody, s) @@ -150,7 +149,7 @@ func TestNewMultipart(t *testing.T) { func TestNewMultipart_read(t *testing.T) { e := testMakeMultipart() - if b, err := ioutil.ReadAll(e.Body); err != nil { + if b, err := io.ReadAll(e.Body); err != nil { t.Error("Expected no error while reading multipart body, got", err) } else if s := string(b); s != testMultipartBody { t.Errorf("Expected %q as multipart body but got %q", testMultipartBody, s) @@ -172,9 +171,9 @@ func TestRead_single(t *testing.T) { t.Fatalf("Read() = %v", err) } - b, err := ioutil.ReadAll(e.Body) + b, err := io.ReadAll(e.Body) if err != nil { - t.Fatalf("ioutil.ReadAll() = %v", err) + t.Fatalf("io.ReadAll() = %v", err) } expected := "Message body" @@ -475,11 +474,11 @@ func TestNew_unknownTransferEncoding(t *testing.T) { if !IsUnknownEncoding(err) { t.Fatal("New(unknown transfer encoding): expected an error that verifies IsUnknownEncoding") } - if !errors.As(err, &UnknownEncodingError{}) { - t.Fatal("New(unknown transfer encoding): expected an error that verifies errors.As(err, &EncodingError{})") + if _, ok := errors.AsType[UnknownEncodingError](err); !ok { + t.Fatal("New(unknown transfer encoding): expected an error that verifies errors.AsType[UnknownEncodingError]") } - if b, err := ioutil.ReadAll(e.Body); err != nil { + if b, err := io.ReadAll(e.Body); err != nil { t.Error("Expected no error while reading entity body, got", err) } else if s := string(b); s != expected { t.Errorf("Expected %q as entity body but got %q", expected, s) @@ -501,7 +500,7 @@ func TestNew_unknownCharset(t *testing.T) { t.Fatal("New(unknown charset): expected an error that verifies IsUnknownCharset") } - if b, err := ioutil.ReadAll(e.Body); err != nil { + if b, err := io.ReadAll(e.Body); err != nil { t.Error("Expected no error while reading entity body, got", err) } else if s := string(b); s != expected { t.Errorf("Expected %q as entity body but got %q", expected, s) @@ -537,7 +536,7 @@ func TestNew_paddedBase64(t *testing.T) { t.Fatal("New(padded Base64): expected no error, got", err) } - if b, err := ioutil.ReadAll(e.Body); err != nil { + if b, err := io.ReadAll(e.Body); err != nil { t.Error("Expected no error while reading entity body, got", err) } else if s := string(b); s != expected { t.Errorf("Expected %q as entity body but got %q", expected, s) @@ -565,7 +564,7 @@ func walkCollect(e *Entity) ([]testWalkPart, error) { err := e.Walk(func(path []int, part *Entity, err error) error { var body string if part.MultipartReader() == nil { - b, err := ioutil.ReadAll(part.Body) + b, err := io.ReadAll(part.Body) if err != nil { return err } diff --git a/mail/header.go b/mail/header.go index 4dd89ef..f632567 100644 --- a/mail/header.go +++ b/mail/header.go @@ -70,7 +70,7 @@ func (p *headerParser) consumeComment() (string, bool) { // '(' already consumed. depth := 1 - var comment string + var comment strings.Builder for { if p.empty() || depth == 0 { break @@ -85,13 +85,13 @@ func (p *headerParser) consumeComment() (string, bool) { } if depth > 0 { - comment += p.s[:1] + comment.WriteString(p.s[:1]) } p.s = p.s[1:] } - return comment, depth == 0 + return comment.String(), depth == 0 } func (p *headerParser) parseAtomText(dot bool) (string, error) { diff --git a/mail/reader_test.go b/mail/reader_test.go index 69297ee..59db8bd 100644 --- a/mail/reader_test.go +++ b/mail/reader_test.go @@ -2,7 +2,6 @@ package mail_test import ( "io" - "io/ioutil" "log" "strings" "testing" @@ -31,7 +30,7 @@ func ExampleReader() { switch h := p.Header.(type) { case *mail.InlineHeader: - b, _ := ioutil.ReadAll(p.Body) + b, _ := io.ReadAll(p.Body) log.Printf("Got text: %v\n", string(b)) case *mail.AttachmentHeader: filename, _ := h.Filename() @@ -92,7 +91,7 @@ func testReader(t *testing.T, r io.Reader) { expectedBody = "I'm Mitsuha." } - if b, err := ioutil.ReadAll(p.Body); err != nil { + if b, err := io.ReadAll(p.Body); err != nil { t.Error("Expected no error while reading part body, but got:", err) } else if string(b) != expectedBody { t.Errorf("Expected part body to be:\n%v\nbut got:\n%v", expectedBody, string(b)) @@ -131,7 +130,7 @@ func TestReader_nonMultipart(t *testing.T) { } expectedBody := "Who are you?" - if b, err := ioutil.ReadAll(p.Body); err != nil { + if b, err := io.ReadAll(p.Body); err != nil { t.Error("Expected no error while reading part body, but got:", err) } else if string(b) != expectedBody { t.Errorf("Expected part body to be:\n%v\nbut got:\n%v", expectedBody, string(b)) @@ -185,7 +184,7 @@ func TestReader_nested(t *testing.T) { } expectedBody := "I forgot." - if b, err := ioutil.ReadAll(p.Body); err != nil { + if b, err := io.ReadAll(p.Body); err != nil { t.Error("Expected no error while reading part body, but got:", err) } else if string(b) != expectedBody { t.Errorf("Expected part body to be:\n%v\nbut got:\n%v", expectedBody, string(b)) diff --git a/textproto/bench_test.go b/textproto/bench_test.go index 549e908..22f86f6 100644 --- a/textproto/bench_test.go +++ b/textproto/bench_test.go @@ -228,7 +228,7 @@ func BenchmarkTextprotoReadHeader(b *testing.B) { r := bufio.NewReader(strings.NewReader(blob)) var err error - for i := 0; i < b.N; i++ { + for b.Loop() { r.Reset(strings.NewReader(blob)) hdr, err = ReadHeader(r) if err != nil { @@ -254,7 +254,7 @@ func BenchmarkStdlibReadHeader(b *testing.B) { tr := textproto.NewReader(r) var err error - for i := 0; i < b.N; i++ { + for b.Loop() { r.Reset(strings.NewReader(blob)) mimeHdr, err = tr.ReadMIMEHeader() if err != nil { diff --git a/textproto/header.go b/textproto/header.go index 666220b..db12566 100644 --- a/textproto/header.go +++ b/textproto/header.go @@ -7,7 +7,7 @@ import ( "fmt" "io" "net/textproto" - "sort" + "slices" "strings" ) @@ -93,8 +93,8 @@ func HeaderFromMap(m map[string][]string) Header { } } - sort.SliceStable(fs, func(i, j int) bool { - return fs[i].k < fs[j].k + slices.SortStableFunc(fs, func(a, b *headerField) int { + return strings.Compare(a.k, b.k) }) return newHeader(fs) @@ -110,12 +110,12 @@ func HeaderFromMap(m map[string][]string) Header { // kv is directly added to the underlying structure and therefore should not be // modified after the AddRaw call. func (h *Header) AddRaw(kv []byte) { - colon := bytes.IndexByte(kv, ':') - if colon == -1 { + rawKey, rawValue, ok := bytes.Cut(kv, []byte(":")) + if !ok { panic("textproto: Header.AddRaw: missing colon") } - k := textproto.CanonicalMIMEHeaderKey(string(trim(kv[:colon]))) - v := trimAroundNewlines(kv[colon+1:]) + k := textproto.CanonicalMIMEHeaderKey(string(trim(rawKey))) + v := trimAroundNewlines(rawValue) if h.m == nil { h.m = make(map[string][]*headerField) @@ -201,9 +201,9 @@ func (h *Header) Del(k string) { delete(h.m, k) // Delete existing keys - for i := len(h.l) - 1; i >= 0; i-- { - if h.l[i].k == k { - h.l = append(h.l[:i], h.l[i+1:]...) + for i, v := range slices.Backward(h.l) { + if v.k == k { + h.l = slices.Delete(h.l, i, i+1) } } } @@ -311,7 +311,7 @@ func (fs *headerFields) Del() { for i, ff := range fs.h.m[f.k] { if ff == f { ok = true - fs.h.m[f.k] = append(fs.h.m[f.k][:i], fs.h.m[f.k][i+1:]...) + fs.h.m[f.k] = slices.Delete(fs.h.m[f.k], i, i+1) if len(fs.h.m[f.k]) == 0 { delete(fs.h.m, f.k) } @@ -322,7 +322,7 @@ func (fs *headerFields) Del() { panic("message: field not found in Header.m") } - fs.h.l = append(fs.h.l[:fs.index()], fs.h.l[fs.index()+1:]...) + fs.h.l = slices.Delete(fs.h.l, fs.index(), fs.index()+1) fs.cur-- } @@ -383,7 +383,7 @@ func (fs *headerFieldsByKey) Del() { for i := range fs.h.l { if f == fs.h.l[i] { ok = true - fs.h.l = append(fs.h.l[:i], fs.h.l[i+1:]...) + fs.h.l = slices.Delete(fs.h.l, i, i+1) break } } @@ -391,7 +391,7 @@ func (fs *headerFieldsByKey) Del() { panic("message: field not found in Header.l") } - fs.h.m[fs.k] = append(fs.h.m[fs.k][:fs.index()], fs.h.m[fs.k][fs.index()+1:]...) + fs.h.m[fs.k] = slices.Delete(fs.h.m[fs.k], fs.index(), fs.index()+1) if len(fs.h.m[fs.k]) == 0 { delete(fs.h.m, fs.k) } @@ -518,13 +518,12 @@ func trimAroundNewlines(v []byte) string { var b strings.Builder b.Grow(len(v)) for { - i := bytes.IndexByte(v, '\n') - if i < 0 { - writeContinued(&b, v) + line, rest, found := bytes.Cut(v, []byte("\n")) + writeContinued(&b, line) + if !found { break } - writeContinued(&b, v[:i]) - v = v[i+1:] + v = rest } return b.String() @@ -596,19 +595,19 @@ func readHeaderInitialLine(r *bufio.Reader, off *int) (line []byte, err error) { func parseHeaderFieldLine(kv []byte, off int) (key, value string, err error) { // Key ends at first colon; should not have trailing spaces but they // appear in the wild, violating specs, so we remove them if present. - i := bytes.IndexByte(kv, ':') - if i < 0 { + rawKey, rawValue, ok := bytes.Cut(kv, []byte(":")) + if !ok { return "", "", &MalformedHeaderError{Kind: MalformedLine, Offset: off} } - keyBytes := trim(kv[:i]) + keyBytes := trim(rawKey) // Verify that there are no invalid characters in the header key. // See RFC 5322 Section 2.2 for _, c := range keyBytes { if !validHeaderKeyByte(c) { lead := 0 - for lead < i && isSpace(kv[lead]) { + for lead < len(rawKey) && isSpace(kv[lead]) { lead++ } return "", "", &MalformedHeaderError{Kind: MalformedKey, Offset: off + lead} @@ -616,7 +615,7 @@ func parseHeaderFieldLine(kv []byte, off int) (key, value string, err error) { } key = textproto.CanonicalMIMEHeaderKey(string(keyBytes)) - value = trimAroundNewlines(kv[i+1:]) + value = trimAroundNewlines(rawValue) return key, value, nil } @@ -747,8 +746,7 @@ func formatHeaderField(k, v string) string { // WriteHeader writes a MIME header to w. func WriteHeader(w io.Writer, h Header) error { - for i := len(h.l) - 1; i >= 0; i-- { - f := h.l[i] + for i, f := range slices.Backward(h.l) { if rawField, err := f.raw(); err == nil { if _, err := w.Write(rawField); err != nil { return err diff --git a/textproto/multipart.go b/textproto/multipart.go index b78af6e..2c0478b 100644 --- a/textproto/multipart.go +++ b/textproto/multipart.go @@ -14,7 +14,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" ) var emptyParams = make(map[string]string) @@ -241,10 +240,7 @@ func (pr partReader) Read(d []byte) (int, error) { if p.n == 0 { return 0, p.err } - n := len(d) - if n > p.n { - n = p.n - } + n := min(len(d), p.n) n, _ = br.Read(d[:n]) p.total += int64(n) p.n -= n @@ -348,7 +344,7 @@ func matchAfterPrefix(buf, prefix []byte, readErr error) int { } func (p *Part) Close() error { - io.Copy(ioutil.Discard, p) + io.Copy(io.Discard, p) return nil } @@ -389,6 +385,7 @@ func (r *MultipartReader) NextPart() (*Part, error) { return nil, io.EOF } if err != nil { + // %v, not %w: wrapping would make a truncated body satisfy errors.Is(err, io.EOF). return nil, fmt.Errorf("multipart: NextPart: %v", err) } diff --git a/textproto/multipart_test.go b/textproto/multipart_test.go index ff6b8c7..82cbec7 100644 --- a/textproto/multipart_test.go +++ b/textproto/multipart_test.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net/textproto" "reflect" "strings" @@ -284,7 +283,7 @@ Oh no, premature EOF! if err != nil { t.Fatalf("didn't get a part") } - _, err = io.Copy(ioutil.Discard, part) + _, err = io.Copy(io.Discard, part) if err != io.ErrUnexpectedEOF { t.Fatalf("expected error io.ErrUnexpectedEOF; got %v", err) } @@ -349,7 +348,7 @@ Body 2 if !reflect.DeepEqual(headerToMap(part.Header), hdr) { t.Errorf("Part %d: part.Header = %v, want %v", i, part.Header, hdr) } - data, err := ioutil.ReadAll(part) + data, err := io.ReadAll(part) expectEq(t, body, string(data), fmt.Sprintf("Part %d body", i)) if err != nil { t.Fatalf("Part %d: ReadAll failed: %v", i, err) @@ -379,7 +378,7 @@ func TestLineContinuation(t *testing.T) { r := NewMultipartReader(strings.NewReader(testBody), "Apple-Mail-2-292336769") - for i := 0; i < 2; i++ { + for range 2 { part, err := r.NextPart() if err != nil { t.Fatalf("didn't get a part") @@ -439,14 +438,14 @@ yO7WvrlwzA0uLzrD+VkKqViwl9IfTBVNFMyc/x9alloiPPlqhQAAAABJRU5ErkJggg== if err != nil { t.Fatalf("reading text/plain part: %v", err) } - if b, err := ioutil.ReadAll(p); string(b) != "*body*\n" || err != nil { + if b, err := io.ReadAll(p); string(b) != "*body*\n" || err != nil { t.Fatalf("reading text/plain part: got %q, %v", b, err) } p, err = mr2.NextPart() if err != nil { t.Fatalf("reading text/html part: %v", err) } - if b, err := ioutil.ReadAll(p); string(b) != "body\n" || err != nil { + if b, err := io.ReadAll(p); string(b) != "body\n" || err != nil { t.Fatalf("reading text/html part: got %q, %v", b, err) } @@ -835,7 +834,7 @@ Cases: t.Errorf("in test %q, NextPart: %v", tt.name, err) continue Cases } - pbody, err := ioutil.ReadAll(p) + pbody, err := io.ReadAll(p) if err != nil { t.Errorf("in test %q, error reading part: %v", tt.name, err) continue Cases @@ -867,7 +866,7 @@ func partsFromReader(r *MultipartReader) ([]headerBody, error) { if err != nil { return nil, fmt.Errorf("NextPart: %v", err) } - pbody, err := ioutil.ReadAll(p) + pbody, err := io.ReadAll(p) if err != nil { return nil, fmt.Errorf("error reading part: %v", err) } @@ -949,7 +948,7 @@ func TestMalformedPartHeaderRecovery(t *testing.T) { if err != nil { t.Fatalf("part 1 NextPart: %v", err) } - b, _ := ioutil.ReadAll(p) + b, _ := io.ReadAll(p) if got, want := string(b), "Hi -- thanks for the call earlier."; got != want { t.Errorf("part 1 body: got %q, want %q", got, want) } @@ -965,7 +964,7 @@ func TestMalformedPartHeaderRecovery(t *testing.T) { if got, want := p.Header.Get("Content-Type"), "text/html; charset=utf-8"; got != want { t.Errorf("part 2 Content-Type: got %q, want %q", got, want) } - b, _ = ioutil.ReadAll(p) + b, _ = io.ReadAll(p) if got, want := string(b), "phish"; got != want { t.Errorf("part 2 body: got %q, want %q", got, want) } @@ -1006,7 +1005,7 @@ func TestMalformedPartHeaderSkip(t *testing.T) { if got := p.Header.Get("Content-Type"); got != "" { t.Errorf("part 1 Content-Type: got %q, want empty", got) } - b, _ := ioutil.ReadAll(p) + b, _ := io.ReadAll(p) if got, want := string(b), "first bad line\r\nsecond bad line\r\n\r\nskipped body"; got != want { t.Errorf("part 1 body: got %q, want %q", got, want) } @@ -1019,7 +1018,7 @@ func TestMalformedPartHeaderSkip(t *testing.T) { if got, want := p.Header.Get("Content-Type"), "text/plain"; got != want { t.Errorf("part 2 Content-Type: got %q, want %q", got, want) } - b, _ = ioutil.ReadAll(p) + b, _ = io.ReadAll(p) if got, want := string(b), "good body"; got != want { t.Errorf("part 2 body: got %q, want %q", got, want) } @@ -1067,7 +1066,7 @@ func TestMalformedPartHeaderPreservesSubBoundary(t *testing.T) { if got, want := ip.Header.Get("Content-Type"), "text/plain"; got != want { t.Errorf("inner Content-Type: got %q, want %q", got, want) } - b, _ := ioutil.ReadAll(ip) + b, _ := io.ReadAll(ip) if got, want := string(b), "real content"; got != want { t.Errorf("inner body: got %q, want %q", got, want) } @@ -1129,7 +1128,7 @@ func TestMalformedPartHeaderInitialLinePreservesLineEnding(t *testing.T) { if !IsMalformedPartHeader(err) || p == nil { t.Fatalf("NextPart: expected a recovered part with IsMalformedPartHeader, got p=%v err=%v", p, err) } - b, _ := ioutil.ReadAll(p) + b, _ := io.ReadAll(p) if got, want := string(b), " initial bad line\r\nsecond bad line\r\n"; got != want { t.Errorf("body: got %q, want %q", got, want) } @@ -1150,7 +1149,7 @@ func TestMalformedPartHeaderPreservesEmptyKeyLine(t *testing.T) { if !IsMalformedPartHeader(err) || p == nil { t.Fatalf("NextPart: expected a recovered part with IsMalformedPartHeader, got p=%v err=%v", p, err) } - b, _ := ioutil.ReadAll(p) + b, _ := io.ReadAll(p) if got, want := string(b), "bad line one\r\n: emptykey\r\nsecond bad line\r\n"; got != want { t.Errorf("body: got %q, want %q", got, want) } @@ -1163,10 +1162,10 @@ func TestMatchAfterPrefix(t *testing.T) { prefix := []byte("\r\n--foo") tests := []struct { - name string - buf []byte - readErr error - want int + name string + buf []byte + readErr error + want int }{ {"buf equals prefix, no err", prefix, nil, 0}, {"buf equals prefix, at EOF", prefix, eof, +1},