1// Copyright 2015 Google LLC
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package gensupport
6
7import (
8	"bytes"
9	"io"
10	"io/ioutil"
11	"reflect"
12	"testing"
13	"testing/iotest"
14
15	"google.golang.org/api/googleapi"
16)
17
18// getChunkAsString reads a chunk from mb, but does not call Next.
19func getChunkAsString(t *testing.T, mb *MediaBuffer) (string, error) {
20	chunk, _, size, err := mb.Chunk()
21
22	buf, e := ioutil.ReadAll(chunk)
23	if e != nil {
24		t.Fatalf("Failed reading chunk: %v", e)
25	}
26	if size != len(buf) {
27		t.Fatalf("reported chunk size doesn't match actual chunk size: got: %v; want: %v", size, len(buf))
28	}
29	return string(buf), err
30}
31
32func TestChunking(t *testing.T) {
33	type testCase struct {
34		data       string // the data to read from the Reader
35		finalErr   error  // error to return after data has been read
36		chunkSize  int
37		wantChunks []string
38	}
39
40	for _, singleByteReads := range []bool{true, false} {
41		for _, tc := range []testCase{
42			{
43				data:       "abcdefg",
44				finalErr:   nil,
45				chunkSize:  3,
46				wantChunks: []string{"abc", "def", "g"},
47			},
48			{
49				data:       "abcdefg",
50				finalErr:   nil,
51				chunkSize:  1,
52				wantChunks: []string{"a", "b", "c", "d", "e", "f", "g"},
53			},
54			{
55				data:       "abcdefg",
56				finalErr:   nil,
57				chunkSize:  7,
58				wantChunks: []string{"abcdefg"},
59			},
60			{
61				data:       "abcdefg",
62				finalErr:   nil,
63				chunkSize:  8,
64				wantChunks: []string{"abcdefg"},
65			},
66			{
67				data:       "abcdefg",
68				finalErr:   io.ErrUnexpectedEOF,
69				chunkSize:  3,
70				wantChunks: []string{"abc", "def", "g"},
71			},
72			{
73				data:       "abcdefg",
74				finalErr:   io.ErrUnexpectedEOF,
75				chunkSize:  8,
76				wantChunks: []string{"abcdefg"},
77			},
78		} {
79			var r io.Reader = &errReader{buf: []byte(tc.data), err: tc.finalErr}
80
81			if singleByteReads {
82				r = iotest.OneByteReader(r)
83			}
84
85			mb := NewMediaBuffer(r, tc.chunkSize)
86			var gotErr error
87			got := []string{}
88			for {
89				chunk, err := getChunkAsString(t, mb)
90				if len(chunk) != 0 {
91					got = append(got, string(chunk))
92				}
93				if err != nil {
94					gotErr = err
95					break
96				}
97				mb.Next()
98			}
99
100			if !reflect.DeepEqual(got, tc.wantChunks) {
101				t.Errorf("Failed reading buffer: got: %v; want:%v", got, tc.wantChunks)
102			}
103
104			expectedErr := tc.finalErr
105			if expectedErr == nil {
106				expectedErr = io.EOF
107			}
108			if gotErr != expectedErr {
109				t.Errorf("Reading buffer error: got: %v; want: %v", gotErr, expectedErr)
110			}
111		}
112	}
113}
114
115func TestChunkCanBeReused(t *testing.T) {
116	er := &errReader{buf: []byte("abcdefg")}
117	mb := NewMediaBuffer(er, 3)
118
119	// expectChunk reads a chunk and checks that it got what was wanted.
120	expectChunk := func(want string, wantErr error) {
121		got, err := getChunkAsString(t, mb)
122		if err != wantErr {
123			t.Errorf("error reading buffer: got: %v; want: %v", err, wantErr)
124		}
125		if !reflect.DeepEqual(got, want) {
126			t.Errorf("Failed reading buffer: got: %q; want:%q", got, want)
127		}
128	}
129	expectChunk("abc", nil)
130	// On second call, should get same chunk again.
131	expectChunk("abc", nil)
132	mb.Next()
133	expectChunk("def", nil)
134	expectChunk("def", nil)
135	mb.Next()
136	expectChunk("g", io.EOF)
137	expectChunk("g", io.EOF)
138	mb.Next()
139	expectChunk("", io.EOF)
140}
141
142func TestPos(t *testing.T) {
143	er := &errReader{buf: []byte("abcdefg")}
144	mb := NewMediaBuffer(er, 3)
145
146	expectChunkAtOffset := func(want int64, wantErr error) {
147		_, off, _, err := mb.Chunk()
148		if err != wantErr {
149			t.Errorf("error reading buffer: got: %v; want: %v", err, wantErr)
150		}
151		if got := off; got != want {
152			t.Errorf("resumable buffer Pos: got: %v; want: %v", got, want)
153		}
154	}
155
156	// We expect the first chunk to be at offset 0.
157	expectChunkAtOffset(0, nil)
158	// Fetching the same chunk should return the same offset.
159	expectChunkAtOffset(0, nil)
160
161	// Calling Next multiple times should only cause off to advance by 3, since off is not advanced until
162	// the chunk is actually read.
163	mb.Next()
164	mb.Next()
165	expectChunkAtOffset(3, nil)
166
167	mb.Next()
168
169	// Load the final 1-byte chunk.
170	expectChunkAtOffset(6, io.EOF)
171
172	// Next will advance 1 byte.  But there are no more chunks, so off will not increase beyond 7.
173	mb.Next()
174	expectChunkAtOffset(7, io.EOF)
175	mb.Next()
176	expectChunkAtOffset(7, io.EOF)
177}
178
179// bytes.Reader implements both Reader and ReaderAt.  The following types
180// implement various combinations of Reader, ReaderAt and ContentTyper, by
181// wrapping bytes.Reader.  All implement at least ReaderAt, so they can be
182// passed to ReaderAtToReader.  The following table summarizes which types
183// implement which interfaces:
184//
185//                 ReaderAt	Reader	ContentTyper
186// reader              x          x
187// typerReader         x          x          x
188// readerAt            x
189// typerReaderAt       x                     x
190
191// reader implements Reader, in addition to ReaderAt.
192type reader struct {
193	r *bytes.Reader
194}
195
196func (r *reader) ReadAt(b []byte, off int64) (n int, err error) {
197	return r.r.ReadAt(b, off)
198}
199
200func (r *reader) Read(b []byte) (n int, err error) {
201	return r.r.Read(b)
202}
203
204// typerReader implements Reader and ContentTyper, in addition to ReaderAt.
205type typerReader struct {
206	r *bytes.Reader
207}
208
209func (tr *typerReader) ReadAt(b []byte, off int64) (n int, err error) {
210	return tr.r.ReadAt(b, off)
211}
212
213func (tr *typerReader) Read(b []byte) (n int, err error) {
214	return tr.r.Read(b)
215}
216
217func (tr *typerReader) ContentType() string {
218	return "ctype"
219}
220
221// readerAt implements only ReaderAt.
222type readerAt struct {
223	r *bytes.Reader
224}
225
226func (ra *readerAt) ReadAt(b []byte, off int64) (n int, err error) {
227	return ra.r.ReadAt(b, off)
228}
229
230// typerReaderAt implements ContentTyper, in addition to ReaderAt.
231type typerReaderAt struct {
232	r *bytes.Reader
233}
234
235func (tra *typerReaderAt) ReadAt(b []byte, off int64) (n int, err error) {
236	return tra.r.ReadAt(b, off)
237}
238
239func (tra *typerReaderAt) ContentType() string {
240	return "ctype"
241}
242
243func TestAdapter(t *testing.T) {
244	data := "abc"
245
246	checkConversion := func(to io.Reader, wantTyper bool) {
247		if _, ok := to.(googleapi.ContentTyper); ok != wantTyper {
248			t.Errorf("reader implements typer? got: %v; want: %v", ok, wantTyper)
249		}
250		if typer, ok := to.(googleapi.ContentTyper); ok && typer.ContentType() != "ctype" {
251			t.Errorf("content type: got: %s; want: ctype", typer.ContentType())
252		}
253		buf, err := ioutil.ReadAll(to)
254		if err != nil {
255			t.Errorf("error reading data: %v", err)
256			return
257		}
258		if !bytes.Equal(buf, []byte(data)) {
259			t.Errorf("failed reading data: got: %s; want: %s", buf, data)
260		}
261	}
262
263	type testCase struct {
264		from      io.ReaderAt
265		wantTyper bool
266	}
267	for _, tc := range []testCase{
268		{
269			from:      &reader{bytes.NewReader([]byte(data))},
270			wantTyper: false,
271		},
272		{
273			// Reader and ContentTyper
274			from:      &typerReader{bytes.NewReader([]byte(data))},
275			wantTyper: true,
276		},
277		{
278			// ReaderAt
279			from:      &readerAt{bytes.NewReader([]byte(data))},
280			wantTyper: false,
281		},
282		{
283			// ReaderAt and ContentTyper
284			from:      &typerReaderAt{bytes.NewReader([]byte(data))},
285			wantTyper: true,
286		},
287	} {
288		to := ReaderAtToReader(tc.from, int64(len(data)))
289		checkConversion(to, tc.wantTyper)
290		// tc.from is a ReaderAt, and should be treated like one, even
291		// if it also implements Reader.  Specifically, it can be
292		// reused and read from the beginning.
293		to = ReaderAtToReader(tc.from, int64(len(data)))
294		checkConversion(to, tc.wantTyper)
295	}
296}
297