55use MongoDB \BSON \Binary ;
66use MongoDB \GridFS \CollectionWrapper ;
77use MongoDB \GridFS \ReadableStream ;
8+ use MongoDB \Tests \CommandObserver ;
9+ use stdClass ;
810
911/**
1012 * Functional tests for the internal ReadableStream class.
@@ -188,6 +190,15 @@ public function testReadBytesWithNegativeLength()
188190 $ stream ->readBytes (-1 );
189191 }
190192
193+ public function testSeekBeforeReading ()
194+ {
195+ $ fileDocument = $ this ->collectionWrapper ->findFileById ('length-10 ' );
196+ $ stream = new ReadableStream ($ this ->collectionWrapper , $ fileDocument );
197+
198+ $ stream ->seek (8 );
199+ $ this ->assertSame ('ij ' , $ stream ->readBytes (2 ));
200+ }
201+
191202 /**
192203 * @expectedException MongoDB\Exception\InvalidArgumentException
193204 * @expectedExceptionMessage $offset must be >= 0 and <= 10; given: 11
@@ -199,4 +210,109 @@ public function testSeekOutOfRange()
199210
200211 $ stream ->seek (11 );
201212 }
213+
214+ /**
215+ * @dataProvider providePreviousChunkSeekOffsetAndBytes
216+ */
217+ public function testSeekPreviousChunk ($ offset , $ length , $ expectedBytes )
218+ {
219+ $ fileDocument = $ this ->collectionWrapper ->findFileById ('length-10 ' );
220+ $ stream = new ReadableStream ($ this ->collectionWrapper , $ fileDocument );
221+
222+ // Read to initialize and advance the chunk iterator to the last chunk
223+ $ this ->assertSame ('abcdefghij ' , $ stream ->readBytes (10 ));
224+
225+ $ commands = [];
226+
227+ (new CommandObserver )->observe (
228+ function () use ($ stream , $ offset , $ length , $ expectedBytes ) {
229+ $ stream ->seek ($ offset );
230+ $ this ->assertSame ($ expectedBytes , $ stream ->readBytes ($ length ));
231+ },
232+ function (stdClass $ command ) use (&$ commands ) {
233+ $ commands [] = key ((array ) $ command );
234+ }
235+ );
236+
237+ $ this ->assertSame (['find ' ], $ commands );
238+ }
239+
240+ public function providePreviousChunkSeekOffsetAndBytes ()
241+ {
242+ return [
243+ [0 , 4 , 'abcd ' ],
244+ [2 , 4 , 'cdef ' ],
245+ [4 , 4 , 'efgh ' ],
246+ [6 , 4 , 'ghij ' ],
247+ ];
248+ }
249+
250+ /**
251+ * @dataProvider provideSameChunkSeekOffsetAndBytes
252+ */
253+ public function testSeekSameChunk ($ offset , $ length , $ expectedBytes )
254+ {
255+ $ fileDocument = $ this ->collectionWrapper ->findFileById ('length-10 ' );
256+ $ stream = new ReadableStream ($ this ->collectionWrapper , $ fileDocument );
257+
258+ // Read to initialize and advance the chunk iterator to the middle chunk
259+ $ this ->assertSame ('abcdef ' , $ stream ->readBytes (6 ));
260+
261+ $ commands = [];
262+
263+ (new CommandObserver )->observe (
264+ function () use ($ stream , $ offset , $ length , $ expectedBytes ) {
265+ $ stream ->seek ($ offset );
266+ $ this ->assertSame ($ expectedBytes , $ stream ->readBytes ($ length ));
267+ },
268+ function (stdClass $ command ) use (&$ commands ) {
269+ $ commands [] = key ((array ) $ command );
270+ }
271+ );
272+
273+ $ this ->assertSame ([], $ commands );
274+ }
275+
276+ public function provideSameChunkSeekOffsetAndBytes ()
277+ {
278+ return [
279+ [4 , 4 , 'efgh ' ],
280+ [6 , 4 , 'ghij ' ],
281+ ];
282+ }
283+
284+ /**
285+ * @dataProvider provideSubsequentChunkSeekOffsetAndBytes
286+ */
287+ public function testSeekSubsequentChunk ($ offset , $ length , $ expectedBytes )
288+ {
289+ $ fileDocument = $ this ->collectionWrapper ->findFileById ('length-10 ' );
290+ $ stream = new ReadableStream ($ this ->collectionWrapper , $ fileDocument );
291+
292+ // Read to initialize the chunk iterator to the first chunk
293+ $ this ->assertSame ('a ' , $ stream ->readBytes (1 ));
294+
295+ $ commands = [];
296+
297+ (new CommandObserver )->observe (
298+ function () use ($ stream , $ offset , $ length , $ expectedBytes ) {
299+ $ stream ->seek ($ offset );
300+ $ this ->assertSame ($ expectedBytes , $ stream ->readBytes ($ length ));
301+ },
302+ function (stdClass $ command ) use (&$ commands ) {
303+ $ commands [] = key ((array ) $ command );
304+ }
305+ );
306+
307+ $ this ->assertSame ([], $ commands );
308+ }
309+
310+ public function provideSubsequentChunkSeekOffsetAndBytes ()
311+ {
312+ return [
313+ [4 , 4 , 'efgh ' ],
314+ [6 , 4 , 'ghij ' ],
315+ [8 , 2 , 'ij ' ],
316+ ];
317+ }
202318}
0 commit comments