ILIAS  release_8 Revision v8.24
StreamTest.php
Go to the documentation of this file.
1<?php
2
4
6use Mockery;
7use PHPUnit\Framework\TestCase;
8
9/******************************************************************************
10 *
11 * This file is part of ILIAS, a powerful learning management system.
12 *
13 * ILIAS is licensed with the GPL-3.0, you should have received a copy
14 * of said license along with the source code.
15 *
16 * If this is not the case or you just want to try ILIAS, you'll find
17 * us at:
18 * https://www.ilias.de
19 * https://github.com/ILIAS-eLearning
20 *
21 *****************************************************************************/
32class StreamTest extends TestCase
33{
37 public static $functions;
38
39 private function createResource($content, $mode)
40 {
41 //call the root fopen function \ required!
42 return \fopen("data://text/plain,$content", $mode);
43 }
44
48 protected function setUp(): void
49 {
50 parent::setUp();
51
52 self::$functions = Mockery::mock();
53 }
54
59 public function testDetachWhichShouldSucceed(): void
60 {
61 $content = 'awesome content stream';
62 $mode = 'r';
63 $resource = $this->createResource($content, $mode);
64
65 $subject = new Stream($resource);
66 $detachedResource = $subject->detach();
67
68 //check that the resource is valid.
69 $this->assertTrue(is_resource($detachedResource));
70 $this->assertSame($resource, $detachedResource);
71
72 //Can't test the subject because psr-7 defines that the stream is in an unusable after the detach operation.
73 }
74
80 {
81 $content = 'awesome content stream';
82 $mode = 'r';
83 $resource = $this->createResource($content, $mode);
84
85 $subject = new Stream($resource);
86
87 //check that the detached resource is valid.
88 $detachedResource = $subject->detach();
89 $this->assertTrue(is_resource($detachedResource));
90
91 //must be null because the stream was already detached.
92 $detachedResource = $subject->detach();
93 $this->assertNull($detachedResource);
94 }
95
101 {
102 $content = 'awesome content stream';
103 $correctSize = strlen($content);
104 $mode = 'r';
105 $resource = $this->createResource($content, $mode);
106
107 $subject = new Stream($resource);
108
109 $size = $subject->getSize();
110 $this->assertSame($correctSize, $size);
111 }
112
118 {
119 $content = 'awesome content stream';
120 $correctSize = 900;
121 $mode = 'r';
122 $resource = $this->createResource($content, $mode);
123 $options = new StreamOptions([], $correctSize);
124
125 $subject = new Stream($resource, $options);
126
127 $size = $subject->getSize();
128 $this->assertSame($correctSize, $size);
129 }
130
136 {
137 $content = 'awesome content stream';
138 $mode = 'r';
139 $resource = $this->createResource($content, $mode);
140
141 $subject = new Stream($resource);
142 $subject->detach();
143
144 $size = $subject->getSize();
145 $this->assertNull($size);
146 }
147
152 public function testCloseWhichShouldSucceed(): void
153 {
154 $content = 'awesome content stream';
155 $mode = 'r';
156 $resource = $this->createResource($content, $mode);
157
158 $subject = new Stream($resource);
159
160 $subject->close();
161 $this->assertFalse(is_resource($resource));
162 }
163
169 {
170 $content = 'awesome content stream';
171 $mode = 'r';
172 $resource = $this->createResource($content, $mode);
173
174 $subject = new Stream($resource);
175
176 $actualResource = $subject->detach();
177 $subject->close();
178
179 $this->assertTrue(is_resource($actualResource));
180 }
181
186 public function testTellWhichShouldSucceed(): void
187 {
188 $content = 'awesome content stream';
189 $mode = 'r';
190 $offset = 5;
191 $resource = $this->createResource($content, $mode);
192 fseek($resource, $offset);
193
194 $subject = new Stream($resource);
195
196 $actualPosition = $subject->tell();
197 $this->assertSame($offset, $actualPosition);
198 }
199
205 {
206 $content = 'awesome content stream';
207 $mode = 'r';
208 $resource = $this->createResource($content, $mode);
209
210 $subject = new Stream($resource);
211 $subject->detach();
212
213 $this->expectException(\RuntimeException::class);
214 $this->expectExceptionMessage('Stream is detached');
215
216 $subject->tell();
217 }
218
224 {
225 $content = 'awesome content stream';
226 $mode = 'r';
227 $resource = $this->createResource($content, $mode);
228
229 //load mock class
230 $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
231 $functionMock->shouldReceive('ftell')
232 ->once()
233 ->with($resource)
234 ->andReturn(false);
235
236 $functionMock->shouldReceive('fclose')
237 ->once()
238 ->with($resource);
239
240 $subject = new Stream($resource);
241
242 $this->expectException(\RuntimeException::class);
243 $this->expectExceptionMessage('Unable to determine stream position');
244
245 $subject->tell();
246 }
247
252 public function testEofWhichShouldSucceed(): void
253 {
254 $content = 'awesome content stream';
255 $mode = 'r';
256 $offset = strlen($content); // end of stream
257 $resource = $this->createResource($content, $mode);
258 fseek($resource, $offset); // seek to end of stream
259 fgets($resource, 2); // we need to hit the end of the stream or eof returns false. (https://bugs.php.net/bug.php?id=35136)
260
261 $subject = new Stream($resource);
262
263 $endOfFileReached = $subject->eof();
264 $this->assertTrue($endOfFileReached);
265 }
266
272 {
273 $content = 'awesome content stream';
274 $mode = 'r';
275 $resource = $this->createResource($content, $mode);
276
277 $subject = new Stream($resource);
278 $subject->detach();
279
280 $this->expectException(\RuntimeException::class);
281 $this->expectExceptionMessage('Stream is detached');
282
283 $subject->eof();
284 }
285
286
291 public function testSeekWhichShouldSucceed(): void
292 {
293 $content = 'awesome content stream';
294 $mode = 'r';
295 $offset = 5;
296 $resource = $this->createResource($content, $mode);
297
298 $subject = new Stream($resource);
299
300 $subject->seek($offset);
301 $this->assertSame($offset, ftell($resource));
302 }
303
309 {
310 $content = 'awesome content stream';
311 $mode = 'r';
312 $offset = 5;
313 $resource = $this->createResource($content, $mode);
314
315 $subject = new Stream($resource);
316 $subject->detach();
317
318 $this->expectException(\RuntimeException::class);
319 $this->expectExceptionMessage('Stream is detached');
320
321 $subject->seek($offset);
322 }
323
329 {
330 $content = 'awesome content stream';
331 $mode = 'r';
332 $offset = 5;
333 $resource = $this->createResource($content, $mode);
334
335 $subjectMock = Mockery::mock(Stream::class . '[isSeekable]', [$resource]);
336
337 $subjectMock
338 ->shouldReceive('isSeekable')
339 ->once()
340 ->andReturn(false);
341
342 $this->expectException(\RuntimeException::class);
343 $this->expectExceptionMessage('Stream is not seekable');
344
345 $subjectMock->seek($offset);
346 }
347
353 {
354 $content = 'awesome content stream';
355 $mode = 'r';
356 $offset = 5;
357 $whence = SEEK_SET;
358 $resource = $this->createResource($content, $mode);
359
360 $subject = new Stream($resource);
361
362 //load mock class
363 $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
364 $functionMock->shouldReceive('fseek')
365 ->once()
366 ->withArgs([$resource, $offset, $whence])
367 ->andReturn(-1);
368
369 $functionMock->shouldReceive('fclose')
370 ->once()
371 ->with($resource);
372
373 $this->expectException(\RuntimeException::class);
374 $this->expectExceptionMessage("Unable to seek to stream position \"$offset\" with whence \"$whence\"");
375
376 $subject->seek($offset);
377 }
378
383 public function testReadWhichShouldSucceed(): void
384 {
385 $content = 'awesome content stream';
386 $expectedResult = "awesome";
387 $mode = 'r';
388 $length = 7;
389 $resource = $this->createResource($content, $mode);
390
391 $subject = new Stream($resource);
392
393 $text = $subject->read($length);
394 $this->assertSame($expectedResult, $text);
395 }
396
402 {
403 $content = 'awesome content stream';
404 $expectedResult = "";
405 $mode = 'r';
406 $length = 0;
407 $resource = $this->createResource($content, $mode);
408
409 $subject = new Stream($resource);
410
411 $text = $subject->read($length);
412 $this->assertSame($expectedResult, $text);
413 }
414
420 {
421 $content = 'awesome content stream';
422 $mode = 'r';
423 $length = 7;
424 $resource = $this->createResource($content, $mode);
425
426 $subject = new Stream($resource);
427 $subject->detach();
428
429 $this->expectException(\RuntimeException::class);
430 $this->expectExceptionMessage('Stream is detached');
431
432 $subject->read($length);
433 }
434
440 {
441 $content = 'awesome content stream';
442 $mode = 'r';
443 $length = -2;
444 $resource = $this->createResource($content, $mode);
445
446 $subject = new Stream($resource);
447
448 $this->expectException(\RuntimeException::class);
449 $this->expectExceptionMessage('Length parameter must not be negative');
450
451 $subject->read($length);
452 }
453
459 {
460 $content = 'awesome content stream';
461 $mode = 'w';
462 $length = 3;
463 $resource = $this->createResource($content, $mode);
464
465 $subject = new Stream($resource);
466
467 $this->expectException(\RuntimeException::class);
468 $this->expectExceptionMessage('Can not read from non-readable stream');
469
470 $subject->read($length);
471 }
472
478 {
479 $content = 'awesome content stream';
480 $mode = 'r';
481 $length = 3;
482 $resource = $this->createResource($content, $mode);
483
484 $subject = new Stream($resource);
485
486 //load mock class
487 $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
488
489 $functionMock->shouldReceive('fread')
490 ->once()
491 ->withArgs([$resource, $length])
492 ->andReturn(false);
493
494 $functionMock->shouldReceive('fclose')
495 ->once()
496 ->with($resource);
497
498 $this->expectException(\RuntimeException::class);
499 $this->expectExceptionMessage('Unable to read from stream');
500
501 $subject->read($length);
502 }
503
508 public function testGetContentsWhichShouldSucceed(): void
509 {
510 $content = 'awesome content stream';
511 $mode = 'r';
512 $resource = $this->createResource($content, $mode);
513
514 $subject = new Stream($resource);
515
516 $text = $subject->getContents();
517 $this->assertSame($content, $text);
518 }
519
525 {
526 $content = 'awesome content stream';
527 $mode = 'r';
528 $resource = $this->createResource($content, $mode);
529
530 $subject = new Stream($resource);
531 $subject->detach();
532
533 $this->expectException(\RuntimeException::class);
534 $this->expectExceptionMessage('Stream is detached');
535
536 $subject->getContents();
537 }
538
544 {
545 $content = 'awesome content stream';
546 $mode = 'r';
547 $resource = $this->createResource($content, $mode);
548
549 $subject = new Stream($resource);
550
551 //load mock class
552 $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
553
554 $functionMock->shouldReceive('stream_get_contents')
555 ->once()
556 ->with($resource)
557 ->andReturn(false);
558
559 $functionMock->shouldReceive('fclose')
560 ->once()
561 ->with($resource);
562
563 $this->expectException(\RuntimeException::class);
564 $this->expectExceptionMessage('Unable to read stream contents');
565
566 $subject->getContents();
567 }
568
573 public function testToStringWhichShouldSucceed(): void
574 {
575 $content = 'awesome content stream';
576 $mode = 'r';
577 $resource = $this->createResource($content, $mode);
578
579 $subject = new Stream($resource);
580
581 $text = $subject->__toString();
582 $this->assertSame($content, $text);
583 }
584
592 {
593 $content = 'awesome content stream';
594 $expectedResult = '';
595 $mode = 'r';
596 $resource = $this->createResource($content, $mode);
597
598 $subject = Mockery::mock(Stream::class . '[rewind]', [$resource]);
599
600 $subject->shouldDeferMissing();
601 $subject->shouldReceive('rewind')
602 ->once()
603 ->andThrow(\RuntimeException::class);
604
605 $text = $subject->__toString();
606 $this->assertSame($expectedResult, $text);
607 }
608
613 public function testWriteWhichShouldSucceed(): void
614 {
615 $content = 'awesome content stream';
616 $newContent = '!';
617 $byteCount = strlen($newContent);
618 $mode = 'r+';
619 $resource = fopen('php://memory', $mode);
620 PHPStreamFunctions::fwrite($resource, $content);
621
622 $subject = new Stream($resource);
623 $currentSize = $subject->getSize();
624
625 $numberOfBytesWritten = $subject->write($newContent);
626 $newSize = $subject->getSize();
627
628 $this->assertSame($byteCount, $numberOfBytesWritten, 'The count of bytes passed to write must match the written bytes after the operation.');
629 $this->assertGreaterThan($currentSize, $newSize, 'The new size must be grater than the old size because we wrote to the stream.');
630 }
631
637 {
638 $content = 'awesome content stream';
639 $newContent = '!';
640 $mode = 'w';
641 $resource = $this->createResource($content, $mode);
642
643 $subject = new Stream($resource);
644 $subject->detach();
645
646 $this->expectException(\RuntimeException::class);
647 $this->expectExceptionMessage('Stream is detached');
648
649 $subject->write($newContent);
650 }
651
657 {
658 $content = 'awesome content stream';
659 $newContent = '!';
660 $mode = 'r';
661 $resource = $this->createResource($content, $mode);
662
663 $subject = new Stream($resource);
664
665 $this->expectException(\RuntimeException::class);
666 $this->expectExceptionMessage('Can not write to a non-writable stream');
667
668 $subject->write($newContent);
669 }
670
676 {
677 $content = 'awesome content stream';
678 $newContent = '!';
679 $mode = 'a+';
680 $resource = $this->createResource($content, $mode);
681
682 $subject = new Stream($resource);
683
684 //load mock class
685 $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
686
687 $functionMock->shouldReceive('fwrite')
688 ->once()
689 ->withArgs([$resource, $newContent])
690 ->andReturn(false);
691
692 $functionMock->shouldReceive('fclose')
693 ->once()
694 ->with($resource);
695
696 $this->expectException(\RuntimeException::class);
697 $this->expectExceptionMessage('Unable to write to stream');
698
699 $subject->write($newContent);
700 }
701}
testDetachDoubleInvocationWhichShouldFail()
@Test @small
Definition: StreamTest.php:79
testGetSizeWithDetachedStreamWhichShouldFail()
@Test @small
Definition: StreamTest.php:135
testDetachWhichShouldSucceed()
@Test @small
Definition: StreamTest.php:59
testGetContentsWithFailingStreamGetContentsCallWhichShouldFail()
@Test @small
Definition: StreamTest.php:543
testGetSizeWithOptionsWhichShouldSucceed()
@Test @small
Definition: StreamTest.php:117
testSeekWithNotSeekableStreamWhichShouldFail()
@Test @small
Definition: StreamTest.php:328
testWriteWithFailingFwriteCallWhichShouldFail()
@Test @small
Definition: StreamTest.php:675
testSeekWithFseekFailureWhichShouldFail()
@Test @small
Definition: StreamTest.php:352
testTellWithFtellFailureWhichShouldFail()
@Test @small
Definition: StreamTest.php:223
testEofWithDetachedStreamWhichShouldFail()
@Test @small
Definition: StreamTest.php:271
testToStringWhichShouldSucceed()
@Test @small
Definition: StreamTest.php:573
testReadWithFailingFreadCallWhichShouldFail()
@Test @small
Definition: StreamTest.php:477
testReadWithZeroLengthWhichShouldSucceed()
@Test @small
Definition: StreamTest.php:401
testToStringWithErrorWhichShouldSucceed()
@Test @small
Definition: StreamTest.php:591
testWriteWithReadOnlyStreamWhichShouldFail()
@Test @small
Definition: StreamTest.php:656
testGetContentsWithDetachedStreamWhichShouldFail()
@Test @small
Definition: StreamTest.php:524
testCloseWithDetachedStreamWhichShouldDoNothing()
@Test @small
Definition: StreamTest.php:168
testTellWithDetachedStreamWhichShouldFail()
@Test @small
Definition: StreamTest.php:204
testWriteWithDetachedStreamWhichShouldFail()
@Test @small
Definition: StreamTest.php:636
testReadWithDetachedStreamWhichShouldFail()
@Test @small
Definition: StreamTest.php:419
testGetSizeWithStatsWhichShouldSucceed()
@Test @small
Definition: StreamTest.php:100
testSeekWithDetachedStreamWhichShouldFail()
@Test @small
Definition: StreamTest.php:308
testGetContentsWhichShouldSucceed()
@Test @small
Definition: StreamTest.php:508
testReadWithUnreadableStreamWhichShouldFail()
@Test @small
Definition: StreamTest.php:458
testReadWithNegativeLengthWhichShouldFail()
@Test @small
Definition: StreamTest.php:439
static fwrite($handle, string $string, ?int $length=null)