ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
StreamTest.php
Go to the documentation of this file.
1 <?php
2 
19 namespace ILIAS\Filesystem\Stream;
20 
22 use Mockery;
24 
34 class StreamTest extends TestCase
35 {
39  public static $functions;
40 
41  private function createResource(string $content, string $mode)
42  {
43  //call the root fopen function \ required!
44  return \fopen("data://text/plain,$content", $mode);
45  }
46 
47 
48  protected function setUp(): void
49  {
50  parent::setUp();
51 
52  self::$functions = Mockery::mock();
53  }
54 
55 
56  public function testDetachWhichShouldSucceed(): void
57  {
58  $content = 'awesome content stream';
59  $mode = 'r';
60  $resource = $this->createResource($content, $mode);
61 
62  $subject = new Stream($resource);
63  $detachedResource = $subject->detach();
64 
65  //check that the resource is valid.
66  $this->assertTrue(is_resource($detachedResource));
67  $this->assertSame($resource, $detachedResource);
68 
69  //Can't test the subject because psr-7 defines that the stream is in an unusable after the detach operation.
70  }
71 
72 
74  {
75  $content = 'awesome content stream';
76  $mode = 'r';
77  $resource = $this->createResource($content, $mode);
78 
79  $subject = new Stream($resource);
80 
81  //check that the detached resource is valid.
82  $detachedResource = $subject->detach();
83  $this->assertTrue(is_resource($detachedResource));
84 
85  //must be null because the stream was already detached.
86  $detachedResource = $subject->detach();
87  $this->assertNull($detachedResource);
88  }
89 
90 
92  {
93  $content = 'awesome content stream';
94  $correctSize = strlen($content);
95  $mode = 'r';
96  $resource = $this->createResource($content, $mode);
97 
98  $subject = new Stream($resource);
99 
100  $size = $subject->getSize();
101  $this->assertSame($correctSize, $size);
102  }
103 
104 
106  {
107  $content = 'awesome content stream';
108  $correctSize = 900;
109  $mode = 'r';
110  $resource = $this->createResource($content, $mode);
111  $options = new StreamOptions([], $correctSize);
112 
113  $subject = new Stream($resource, $options);
114 
115  $size = $subject->getSize();
116  $this->assertSame($correctSize, $size);
117  }
118 
120  {
121  $content = 'awesome content stream';
122  $mode = 'r';
123  $resource = $this->createResource($content, $mode);
124 
125  $subject = new Stream($resource);
126  $subject->detach();
127 
128  $size = $subject->getSize();
129  $this->assertNull($size);
130  }
131 
132  public function testCloseWhichShouldSucceed(): void
133  {
134  $content = 'awesome content stream';
135  $mode = 'r';
136  $resource = $this->createResource($content, $mode);
137 
138  $subject = new Stream($resource);
139 
140  $subject->close();
141  $this->assertFalse(is_resource($resource));
142  }
143 
145  {
146  $content = 'awesome content stream';
147  $mode = 'r';
148  $resource = $this->createResource($content, $mode);
149 
150  $subject = new Stream($resource);
151 
152  $actualResource = $subject->detach();
153  $subject->close();
154 
155  $this->assertTrue(is_resource($actualResource));
156  }
157 
158  public function testTellWhichShouldSucceed(): void
159  {
160  $content = 'awesome content stream';
161  $mode = 'r';
162  $offset = 5;
163  $resource = $this->createResource($content, $mode);
164  fseek($resource, $offset);
165 
166  $subject = new Stream($resource);
167 
168  $actualPosition = $subject->tell();
169  $this->assertSame($offset, $actualPosition);
170  }
171 
173  {
174  $content = 'awesome content stream';
175  $mode = 'r';
176  $resource = $this->createResource($content, $mode);
177 
178  $subject = new Stream($resource);
179  $subject->detach();
180 
181  $this->expectException(\RuntimeException::class);
182  $this->expectExceptionMessage('Stream is detached');
183 
184  $subject->tell();
185  }
186 
188  {
189  $content = 'awesome content stream';
190  $mode = 'r';
191  $resource = $this->createResource($content, $mode);
192 
193  //load mock class
194  $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
195  $functionMock->shouldReceive('ftell')
196  ->once()
197  ->with($resource)
198  ->andReturn(false);
199 
200  $functionMock->shouldReceive('fclose')
201  ->once()
202  ->with($resource);
203 
204  $subject = new Stream($resource);
205 
206  $this->expectException(\RuntimeException::class);
207  $this->expectExceptionMessage('Unable to determine stream position');
208 
209  $subject->tell();
210  }
211 
216  public function testEofWhichShouldSucceed(): void
217  {
218  $content = 'awesome content stream';
219  $mode = 'r';
220  $offset = strlen($content); // end of stream
221  $resource = $this->createResource($content, $mode);
222  fseek($resource, $offset); // seek to end of stream
223  fgets($resource, 2); // we need to hit the end of the stream or eof returns false. (https://bugs.php.net/bug.php?id=35136)
224 
225  $subject = new Stream($resource);
226 
227  $endOfFileReached = $subject->eof();
228  $this->assertTrue($endOfFileReached);
229  }
230 
236  {
237  $content = 'awesome content stream';
238  $mode = 'r';
239  $resource = $this->createResource($content, $mode);
240 
241  $subject = new Stream($resource);
242  $subject->detach();
243 
244  $this->expectException(\RuntimeException::class);
245  $this->expectExceptionMessage('Stream is detached');
246 
247  $subject->eof();
248  }
249 
250 
255  public function testSeekWhichShouldSucceed(): void
256  {
257  $content = 'awesome content stream';
258  $mode = 'r';
259  $offset = 5;
260  $resource = $this->createResource($content, $mode);
261 
262  $subject = new Stream($resource);
263 
264  $subject->seek($offset);
265  $this->assertSame($offset, ftell($resource));
266  }
267 
273  {
274  $content = 'awesome content stream';
275  $mode = 'r';
276  $offset = 5;
277  $resource = $this->createResource($content, $mode);
278 
279  $subject = new Stream($resource);
280  $subject->detach();
281 
282  $this->expectException(\RuntimeException::class);
283  $this->expectExceptionMessage('Stream is detached');
284 
285  $subject->seek($offset);
286  }
287 
293  {
294  $content = 'awesome content stream';
295  $mode = 'r';
296  $offset = 5;
297  $resource = $this->createResource($content, $mode);
298 
299  $subjectMock = Mockery::mock(Stream::class . '[isSeekable]', [$resource]);
300 
301  $subjectMock
302  ->shouldReceive('isSeekable')
303  ->once()
304  ->andReturn(false);
305 
306  $this->expectException(\RuntimeException::class);
307  $this->expectExceptionMessage('Stream is not seekable');
308 
309  $subjectMock->seek($offset);
310  }
311 
317  {
318  $content = 'awesome content stream';
319  $mode = 'r';
320  $offset = 5;
321  $whence = SEEK_SET;
322  $resource = $this->createResource($content, $mode);
323 
324  $subject = new Stream($resource);
325 
326  //load mock class
327  $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
328  $functionMock->shouldReceive('fseek')
329  ->once()
330  ->withArgs([$resource, $offset, $whence])
331  ->andReturn(-1);
332 
333  $functionMock->shouldReceive('fclose')
334  ->once()
335  ->with($resource);
336 
337  $this->expectException(\RuntimeException::class);
338  $this->expectExceptionMessage("Unable to seek to stream position \"$offset\" with whence \"$whence\"");
339 
340  $subject->seek($offset);
341  }
342 
347  public function testReadWhichShouldSucceed(): void
348  {
349  $content = 'awesome content stream';
350  $expectedResult = "awesome";
351  $mode = 'r';
352  $length = 7;
353  $resource = $this->createResource($content, $mode);
354 
355  $subject = new Stream($resource);
356 
357  $text = $subject->read($length);
358  $this->assertSame($expectedResult, $text);
359  }
360 
366  {
367  $content = 'awesome content stream';
368  $expectedResult = "";
369  $mode = 'r';
370  $length = 0;
371  $resource = $this->createResource($content, $mode);
372 
373  $subject = new Stream($resource);
374 
375  $text = $subject->read($length);
376  $this->assertSame($expectedResult, $text);
377  }
378 
384  {
385  $content = 'awesome content stream';
386  $mode = 'r';
387  $length = 7;
388  $resource = $this->createResource($content, $mode);
389 
390  $subject = new Stream($resource);
391  $subject->detach();
392 
393  $this->expectException(\RuntimeException::class);
394  $this->expectExceptionMessage('Stream is detached');
395 
396  $subject->read($length);
397  }
398 
404  {
405  $content = 'awesome content stream';
406  $mode = 'r';
407  $length = -2;
408  $resource = $this->createResource($content, $mode);
409 
410  $subject = new Stream($resource);
411 
412  $this->expectException(\RuntimeException::class);
413  $this->expectExceptionMessage('Length parameter must not be negative');
414 
415  $subject->read($length);
416  }
417 
423  {
424  $content = 'awesome content stream';
425  $mode = 'w';
426  $length = 3;
427  $resource = $this->createResource($content, $mode);
428 
429  $subject = new Stream($resource);
430 
431  $this->expectException(\RuntimeException::class);
432  $this->expectExceptionMessage('Can not read from non-readable stream');
433 
434  $subject->read($length);
435  }
436 
442  {
443  $content = 'awesome content stream';
444  $mode = 'r';
445  $length = 3;
446  $resource = $this->createResource($content, $mode);
447 
448  $subject = new Stream($resource);
449 
450  //load mock class
451  $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
452 
453  $functionMock->shouldReceive('fread')
454  ->once()
455  ->withArgs([$resource, $length])
456  ->andReturn(false);
457 
458  $functionMock->shouldReceive('fclose')
459  ->once()
460  ->with($resource);
461 
462  $this->expectException(\RuntimeException::class);
463  $this->expectExceptionMessage('Unable to read from stream');
464 
465  $subject->read($length);
466  }
467 
472  public function testGetContentsWhichShouldSucceed(): void
473  {
474  $content = 'awesome content stream';
475  $mode = 'r';
476  $resource = $this->createResource($content, $mode);
477 
478  $subject = new Stream($resource);
479 
480  $text = $subject->getContents();
481  $this->assertSame($content, $text);
482  }
483 
489  {
490  $content = 'awesome content stream';
491  $mode = 'r';
492  $resource = $this->createResource($content, $mode);
493 
494  $subject = new Stream($resource);
495  $subject->detach();
496 
497  $this->expectException(\RuntimeException::class);
498  $this->expectExceptionMessage('Stream is detached');
499 
500  $subject->getContents();
501  }
502 
508  {
509  $content = 'awesome content stream';
510  $mode = 'r';
511  $resource = $this->createResource($content, $mode);
512 
513  $subject = new Stream($resource);
514 
515  //load mock class
516  $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
517 
518  $functionMock->shouldReceive('stream_get_contents')
519  ->once()
520  ->with($resource)
521  ->andReturn(false);
522 
523  $functionMock->shouldReceive('fclose')
524  ->once()
525  ->with($resource);
526 
527  $this->expectException(\RuntimeException::class);
528  $this->expectExceptionMessage('Unable to read stream contents');
529 
530  $subject->getContents();
531  }
532 
537  public function testToStringWhichShouldSucceed(): void
538  {
539  $content = 'awesome content stream';
540  $mode = 'r';
541  $resource = $this->createResource($content, $mode);
542 
543  $subject = new Stream($resource);
544 
545  $text = $subject->__toString();
546  $this->assertSame($content, $text);
547  }
548 
556  {
557  $content = 'awesome content stream';
558  $expectedResult = '';
559  $mode = 'r';
560  $resource = $this->createResource($content, $mode);
561 
562  $subject = Mockery::mock(Stream::class . '[rewind]', [$resource]);
563 
564  $subject->shouldDeferMissing();
565  $subject->shouldReceive('rewind')
566  ->once()
567  ->andThrow(\RuntimeException::class);
568 
569  $text = $subject->__toString();
570  $this->assertSame($expectedResult, $text);
571  }
572 
577  public function testWriteWhichShouldSucceed(): void
578  {
579  $content = 'awesome content stream';
580  $newContent = '!';
581  $byteCount = strlen($newContent);
582  $mode = 'r+';
583  $resource = fopen('php://memory', $mode);
584  PHPStreamFunctions::fwrite($resource, $content);
585 
586  $subject = new Stream($resource);
587  $currentSize = $subject->getSize();
588 
589  $numberOfBytesWritten = $subject->write($newContent);
590  $newSize = $subject->getSize();
591 
592  $this->assertSame($byteCount, $numberOfBytesWritten, 'The count of bytes passed to write must match the written bytes after the operation.');
593  $this->assertGreaterThan($currentSize, $newSize, 'The new size must be grater than the old size because we wrote to the stream.');
594  }
595 
601  {
602  $content = 'awesome content stream';
603  $newContent = '!';
604  $mode = 'w';
605  $resource = $this->createResource($content, $mode);
606 
607  $subject = new Stream($resource);
608  $subject->detach();
609 
610  $this->expectException(\RuntimeException::class);
611  $this->expectExceptionMessage('Stream is detached');
612 
613  $subject->write($newContent);
614  }
615 
621  {
622  $content = 'awesome content stream';
623  $newContent = '!';
624  $mode = 'r';
625  $resource = $this->createResource($content, $mode);
626 
627  $subject = new Stream($resource);
628 
629  $this->expectException(\RuntimeException::class);
630  $this->expectExceptionMessage('Can not write to a non-writable stream');
631 
632  $subject->write($newContent);
633  }
634 
640  {
641  $content = 'awesome content stream';
642  $newContent = '!';
643  $mode = 'a+';
644  $resource = $this->createResource($content, $mode);
645 
646  $subject = new Stream($resource);
647 
648  //load mock class
649  $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
650 
651  $functionMock->shouldReceive('fwrite')
652  ->once()
653  ->withArgs([$resource, $newContent])
654  ->andReturn(false);
655 
656  $functionMock->shouldReceive('fclose')
657  ->once()
658  ->with($resource);
659 
660  $this->expectException(\RuntimeException::class);
661  $this->expectExceptionMessage('Unable to write to stream');
662 
663  $subject->write($newContent);
664  }
665 }
createResource(string $content, string $mode)
Definition: StreamTest.php:41
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: FileStream.php:19
static fwrite($handle, string $string, ?int $length=null)
The streaming options are used by the stream implementation.