1 package io
2
3 import (
4 "bytes"
5 "errors"
6 "fmt"
7 "io"
8 "testing"
9 )
10
11 type mockReadCloser struct {
12 ReadFn func([]byte) (int, error)
13 CloseFn func() error
14 }
15
16 func (m *mockReadCloser) Read(p []byte) (n int, err error) {
17 if m.ReadFn == nil {
18 return len(p), nil
19 }
20 return m.ReadFn(p)
21 }
22
23 func (m *mockReadCloser) Close() error {
24 if m.CloseFn == nil {
25 return nil
26 }
27 return m.CloseFn()
28 }
29
30 type mockWriteTo struct {
31 mockReadCloser
32 WriteToFn func(io.Writer) (int64, error)
33 }
34
35 func (m *mockWriteTo) WriteTo(w io.Writer) (int64, error) {
36 if m.WriteToFn == nil {
37 return 0, nil
38 }
39 return m.WriteToFn(w)
40 }
41
42 func TestNewSafeReadCloser(t *testing.T) {
43 cases := map[string]struct {
44 ReadCloser io.ReadCloser
45 ReadTest func(*testing.T, *safeReadCloser)
46 CloseTest func(*testing.T, *safeReadCloser)
47 }{
48 "success read and close": {
49 ReadCloser: &mockReadCloser{
50 ReadFn: func(bytes []byte) (int, error) {
51 bytes[0], bytes[1], bytes[2] = 'f', 'o', 'o'
52 return 3, nil
53 },
54 },
55 ReadTest: func(t *testing.T, closer *safeReadCloser) {
56 t.Helper()
57 bs := make([]byte, 3)
58 read, err := closer.Read(bs)
59 if err != nil {
60 t.Errorf("expect no error, got %v", err)
61 }
62 if e, a := "foo", string(bs[:read]); e != a {
63 t.Errorf("expect %v, got %v", e, a)
64 }
65 },
66 CloseTest: func(t *testing.T, closer *safeReadCloser) {
67 t.Helper()
68 if err := closer.Close(); err != nil {
69 t.Errorf("expect no error, got %v", err)
70 }
71 },
72 },
73 "error read": {
74 ReadCloser: &mockReadCloser{
75 ReadFn: func(bytes []byte) (int, error) {
76 return 0, io.ErrUnexpectedEOF
77 },
78 },
79 ReadTest: func(t *testing.T, closer *safeReadCloser) {
80 t.Helper()
81 _, err := closer.Read([]byte{})
82 if err == nil {
83 t.Errorf("expect error, got nil")
84 }
85 if !errors.Is(err, io.ErrUnexpectedEOF) {
86 t.Errorf("expect error to be type %T, got %T", io.ErrUnexpectedEOF, err)
87 }
88 },
89 },
90 "error close": {
91 ReadCloser: &mockReadCloser{
92 CloseFn: func() error {
93 return fmt.Errorf("foobar error")
94 },
95 },
96 CloseTest: func(t *testing.T, closer *safeReadCloser) {
97 t.Helper()
98 if err := closer.Close(); err == nil {
99 t.Error("expect close error, got nil")
100 } else if e, a := "foobar error", err.Error(); e != a {
101 t.Errorf("expect %v, got %v", e, a)
102 }
103 },
104 },
105 }
106
107 for name, tt := range cases {
108 t.Run(name, func(t *testing.T) {
109 sr := NewSafeReadCloser(tt.ReadCloser).(*safeReadCloser)
110 if e, a := false, sr.closed; e != a {
111 t.Errorf("expect %v, got %v", e, a)
112 }
113 if tt.ReadTest != nil {
114 tt.ReadTest(t, sr)
115 }
116 if tt.CloseTest != nil {
117 tt.CloseTest(t, sr)
118 } else {
119 sr.Close()
120 }
121 if e, a := true, sr.closed; e != a {
122 t.Errorf("expect %v, got %v", e, a)
123 }
124 if sr.readCloser != nil {
125 t.Errorf("expect reader to be nil after Close")
126 }
127 if err := sr.Close(); err != nil {
128 t.Errorf("expect subsequent Close returns to be nil, got %v", err)
129 }
130 })
131 }
132 }
133
134 func TestNewSafeReadCloser_WriteTo(t *testing.T) {
135 {
136 rc := &mockWriteTo{}
137 writeToReadCloser := NewSafeReadCloser(rc).(*safeWriteToReadCloser)
138 _, err := writeToReadCloser.WriteTo(nil)
139 if err != nil {
140 t.Errorf("expect no error, got %v", err)
141 }
142
143 err = writeToReadCloser.Close()
144 if err != nil {
145 t.Errorf("expect no error, got %v", err)
146 }
147
148 _, err = writeToReadCloser.WriteTo(nil)
149 if err != io.EOF {
150 t.Errorf("expect %T, got %T", io.EOF, err)
151 }
152 }
153 {
154 rc := &mockWriteTo{
155 WriteToFn: func(writer io.Writer) (int64, error) {
156 write, err := writer.Write([]byte("foo"))
157 return int64(write), err
158 },
159 }
160 writeToReadCloser := NewSafeReadCloser(rc).(*safeWriteToReadCloser)
161 var buf bytes.Buffer
162 _, err := writeToReadCloser.WriteTo(&buf)
163 if err != nil {
164 t.Errorf("expect no error, got %v", err)
165 }
166 if e, a := "foo", buf.String(); e != a {
167 t.Errorf("expect %v, got %v", e, a)
168 }
169 }
170 }
171
View as plain text