ILIAS  trunk Revision v11.0_alpha-1715-g7fc467680fb
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
StreamTestTBD.php
Go to the documentation of this file.
1 <?php
2 
19 namespace ILIAS\Filesystem\Stream;
20 
28 use Mockery;
30 
35 #[BackupGlobals(false)]
36 #[BackupStaticProperties(false)]
37 #[PreserveGlobalState(false)]
38 #[RunTestsInSeparateProcesses]
39 class StreamTest extends TestCase
40 {
44  public static $functions;
45 
46  private function createResource(string $content, string $mode)
47  {
48  //call the root fopen function \ required!
49  return \fopen("data://text/plain,$content", $mode);
50  }
51 
52 
53  protected function setUp(): void
54  {
55  parent::setUp();
56 
57  self::$functions = Mockery::mock();
58  }
59 
60 
61  public function testDetachWhichShouldSucceed(): void
62  {
63  $content = 'awesome content stream';
64  $mode = 'r';
65  $resource = $this->createResource($content, $mode);
66 
67  $subject = new Stream($resource);
68  $detachedResource = $subject->detach();
69 
70  //check that the resource is valid.
71  $this->assertTrue(is_resource($detachedResource));
72  $this->assertSame($resource, $detachedResource);
73 
74  //Can't test the subject because psr-7 defines that the stream is in an unusable after the detach operation.
75  }
76 
77 
79  {
80  $content = 'awesome content stream';
81  $mode = 'r';
82  $resource = $this->createResource($content, $mode);
83 
84  $subject = new Stream($resource);
85 
86  //check that the detached resource is valid.
87  $detachedResource = $subject->detach();
88  $this->assertTrue(is_resource($detachedResource));
89 
90  //must be null because the stream was already detached.
91  $detachedResource = $subject->detach();
92  $this->assertNull($detachedResource);
93  }
94 
95 
97  {
98  $content = 'awesome content stream';
99  $correctSize = strlen($content);
100  $mode = 'r';
101  $resource = $this->createResource($content, $mode);
102 
103  $subject = new Stream($resource);
104 
105  $size = $subject->getSize();
106  $this->assertSame($correctSize, $size);
107  }
108 
109 
111  {
112  $content = 'awesome content stream';
113  $correctSize = 900;
114  $mode = 'r';
115  $resource = $this->createResource($content, $mode);
116  $options = new StreamOptions([], $correctSize);
117 
118  $subject = new Stream($resource, $options);
119 
120  $size = $subject->getSize();
121  $this->assertSame($correctSize, $size);
122  }
123 
125  {
126  $content = 'awesome content stream';
127  $mode = 'r';
128  $resource = $this->createResource($content, $mode);
129 
130  $subject = new Stream($resource);
131  $subject->detach();
132 
133  $size = $subject->getSize();
134  $this->assertNull($size);
135  }
136 
137  public function testCloseWhichShouldSucceed(): void
138  {
139  $content = 'awesome content stream';
140  $mode = 'r';
141  $resource = $this->createResource($content, $mode);
142 
143  $subject = new Stream($resource);
144 
145  $subject->close();
146  $this->assertFalse(is_resource($resource));
147  }
148 
150  {
151  $content = 'awesome content stream';
152  $mode = 'r';
153  $resource = $this->createResource($content, $mode);
154 
155  $subject = new Stream($resource);
156 
157  $actualResource = $subject->detach();
158  $subject->close();
159 
160  $this->assertTrue(is_resource($actualResource));
161  }
162 
163  public function testTellWhichShouldSucceed(): void
164  {
165  $content = 'awesome content stream';
166  $mode = 'r';
167  $offset = 5;
168  $resource = $this->createResource($content, $mode);
169  fseek($resource, $offset);
170 
171  $subject = new Stream($resource);
172 
173  $actualPosition = $subject->tell();
174  $this->assertSame($offset, $actualPosition);
175  }
176 
178  {
179  $content = 'awesome content stream';
180  $mode = 'r';
181  $resource = $this->createResource($content, $mode);
182 
183  $subject = new Stream($resource);
184  $subject->detach();
185 
186  $this->expectException(\RuntimeException::class);
187  $this->expectExceptionMessage('Stream is detached');
188 
189  $subject->tell();
190  }
191 
193  {
194  $content = 'awesome content stream';
195  $mode = 'r';
196  $resource = $this->createResource($content, $mode);
197 
198  //load mock class
199  $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
200  $functionMock->shouldReceive('ftell')
201  ->once()
202  ->with($resource)
203  ->andReturn(false);
204 
205  $functionMock->shouldReceive('fclose')
206  ->once()
207  ->with($resource);
208 
209  $subject = new Stream($resource);
210 
211  $this->expectException(\RuntimeException::class);
212  $this->expectExceptionMessage('Unable to determine stream position');
213 
214  $subject->tell();
215  }
216 
217  #[Test]
218 
219  public function testEofWhichShouldSucceed(): void
220  {
221  $content = 'awesome content stream';
222  $mode = 'r';
223  $offset = strlen($content); // end of stream
224  $resource = $this->createResource($content, $mode);
225  fseek($resource, $offset); // seek to end of stream
226  fgets($resource, 2); // we need to hit the end of the stream or eof returns false. (https://bugs.php.net/bug.php?id=35136)
227 
228  $subject = new Stream($resource);
229 
230  $endOfFileReached = $subject->eof();
231  $this->assertTrue($endOfFileReached);
232  }
233 
234  #[Test]
235 
237  {
238  $content = 'awesome content stream';
239  $mode = 'r';
240  $resource = $this->createResource($content, $mode);
241 
242  $subject = new Stream($resource);
243  $subject->detach();
244 
245  $this->expectException(\RuntimeException::class);
246  $this->expectExceptionMessage('Stream is detached');
247 
248  $subject->eof();
249  }
250 
251 
252  #[Test]
253 
254  public function testSeekWhichShouldSucceed(): void
255  {
256  $content = 'awesome content stream';
257  $mode = 'r';
258  $offset = 5;
259  $resource = $this->createResource($content, $mode);
260 
261  $subject = new Stream($resource);
262 
263  $subject->seek($offset);
264  $this->assertSame($offset, ftell($resource));
265  }
266 
267  #[Test]
268 
270  {
271  $content = 'awesome content stream';
272  $mode = 'r';
273  $offset = 5;
274  $resource = $this->createResource($content, $mode);
275 
276  $subject = new Stream($resource);
277  $subject->detach();
278 
279  $this->expectException(\RuntimeException::class);
280  $this->expectExceptionMessage('Stream is detached');
281 
282  $subject->seek($offset);
283  }
284 
285  #[Test]
286 
288  {
289  $content = 'awesome content stream';
290  $mode = 'r';
291  $offset = 5;
292  $resource = $this->createResource($content, $mode);
293 
294  $subjectMock = Mockery::mock(Stream::class . '[isSeekable]', [$resource]);
295 
296  $subjectMock
297  ->shouldReceive('isSeekable')
298  ->once()
299  ->andReturn(false);
300 
301  $this->expectException(\RuntimeException::class);
302  $this->expectExceptionMessage('Stream is not seekable');
303 
304  $subjectMock->seek($offset);
305  }
306 
307  #[Test]
308 
310  {
311  $content = 'awesome content stream';
312  $mode = 'r';
313  $offset = 5;
314  $whence = SEEK_SET;
315  $resource = $this->createResource($content, $mode);
316 
317  $subject = new Stream($resource);
318 
319  //load mock class
320  $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
321  $functionMock->shouldReceive('fseek')
322  ->once()
323  ->withArgs([$resource, $offset, $whence])
324  ->andReturn(-1);
325 
326  $functionMock->shouldReceive('fclose')
327  ->once()
328  ->with($resource);
329 
330  $this->expectException(\RuntimeException::class);
331  $this->expectExceptionMessage("Unable to seek to stream position \"$offset\" with whence \"$whence\"");
332 
333  $subject->seek($offset);
334  }
335 
336  #[Test]
337 
338  public function testReadWhichShouldSucceed(): void
339  {
340  $content = 'awesome content stream';
341  $expectedResult = "awesome";
342  $mode = 'r';
343  $length = 7;
344  $resource = $this->createResource($content, $mode);
345 
346  $subject = new Stream($resource);
347 
348  $text = $subject->read($length);
349  $this->assertSame($expectedResult, $text);
350  }
351 
352  #[Test]
353 
355  {
356  $content = 'awesome content stream';
357  $expectedResult = "";
358  $mode = 'r';
359  $length = 0;
360  $resource = $this->createResource($content, $mode);
361 
362  $subject = new Stream($resource);
363 
364  $text = $subject->read($length);
365  $this->assertSame($expectedResult, $text);
366  }
367 
368  #[Test]
369 
371  {
372  $content = 'awesome content stream';
373  $mode = 'r';
374  $length = 7;
375  $resource = $this->createResource($content, $mode);
376 
377  $subject = new Stream($resource);
378  $subject->detach();
379 
380  $this->expectException(\RuntimeException::class);
381  $this->expectExceptionMessage('Stream is detached');
382 
383  $subject->read($length);
384  }
385 
386  #[Test]
387 
389  {
390  $content = 'awesome content stream';
391  $mode = 'r';
392  $length = -2;
393  $resource = $this->createResource($content, $mode);
394 
395  $subject = new Stream($resource);
396 
397  $this->expectException(\RuntimeException::class);
398  $this->expectExceptionMessage('Length parameter must not be negative');
399 
400  $subject->read($length);
401  }
402 
403  #[Test]
404 
406  {
407  $content = 'awesome content stream';
408  $mode = 'w';
409  $length = 3;
410  $resource = $this->createResource($content, $mode);
411 
412  $subject = new Stream($resource);
413 
414  $this->expectException(\RuntimeException::class);
415  $this->expectExceptionMessage('Can not read from non-readable stream');
416 
417  $subject->read($length);
418  }
419 
420  #[Test]
421 
423  {
424  $content = 'awesome content stream';
425  $mode = 'r';
426  $length = 3;
427  $resource = $this->createResource($content, $mode);
428 
429  $subject = new Stream($resource);
430 
431  //load mock class
432  $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
433 
434  $functionMock->shouldReceive('fread')
435  ->once()
436  ->withArgs([$resource, $length])
437  ->andReturn(false);
438 
439  $functionMock->shouldReceive('fclose')
440  ->once()
441  ->with($resource);
442 
443  $this->expectException(\RuntimeException::class);
444  $this->expectExceptionMessage('Unable to read from stream');
445 
446  $subject->read($length);
447  }
448 
449  #[Test]
450 
451  public function testGetContentsWhichShouldSucceed(): void
452  {
453  $content = 'awesome content stream';
454  $mode = 'r';
455  $resource = $this->createResource($content, $mode);
456 
457  $subject = new Stream($resource);
458 
459  $text = $subject->getContents();
460  $this->assertSame($content, $text);
461  }
462 
463  #[Test]
464 
466  {
467  $content = 'awesome content stream';
468  $mode = 'r';
469  $resource = $this->createResource($content, $mode);
470 
471  $subject = new Stream($resource);
472  $subject->detach();
473 
474  $this->expectException(\RuntimeException::class);
475  $this->expectExceptionMessage('Stream is detached');
476 
477  $subject->getContents();
478  }
479 
480  #[Test]
481 
483  {
484  $content = 'awesome content stream';
485  $mode = 'r';
486  $resource = $this->createResource($content, $mode);
487 
488  $subject = new Stream($resource);
489 
490  //load mock class
491  $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
492 
493  $functionMock->shouldReceive('stream_get_contents')
494  ->once()
495  ->with($resource)
496  ->andReturn(false);
497 
498  $functionMock->shouldReceive('fclose')
499  ->once()
500  ->with($resource);
501 
502  $this->expectException(\RuntimeException::class);
503  $this->expectExceptionMessage('Unable to read stream contents');
504 
505  $subject->getContents();
506  }
507 
508  #[Test]
509 
510  public function testToStringWhichShouldSucceed(): void
511  {
512  $content = 'awesome content stream';
513  $mode = 'r';
514  $resource = $this->createResource($content, $mode);
515 
516  $subject = new Stream($resource);
517 
518  $text = $subject->__toString();
519  $this->assertSame($content, $text);
520  }
521 
522  #[Test]
523 
525  {
526  $content = 'awesome content stream';
527  $expectedResult = '';
528  $mode = 'r';
529  $resource = $this->createResource($content, $mode);
530 
531  $subject = Mockery::mock(Stream::class . '[rewind]', [$resource]);
532 
533  $subject->shouldDeferMissing();
534  $subject->shouldReceive('rewind')
535  ->once()
536  ->andThrow(\RuntimeException::class);
537 
538  $text = $subject->__toString();
539  $this->assertSame($expectedResult, $text);
540  }
541 
542  #[Test]
543 
544  public function testWriteWhichShouldSucceed(): void
545  {
546  $content = 'awesome content stream';
547  $newContent = '!';
548  $byteCount = strlen($newContent);
549  $mode = 'r+';
550  $resource = fopen('php://memory', $mode);
551  PHPStreamFunctions::fwrite($resource, $content);
552 
553  $subject = new Stream($resource);
554  $currentSize = $subject->getSize();
555 
556  $numberOfBytesWritten = $subject->write($newContent);
557  $newSize = $subject->getSize();
558 
559  $this->assertSame($byteCount, $numberOfBytesWritten, 'The count of bytes passed to write must match the written bytes after the operation.');
560  $this->assertGreaterThan($currentSize, $newSize, 'The new size must be grater than the old size because we wrote to the stream.');
561  }
562 
563  #[Test]
564 
566  {
567  $content = 'awesome content stream';
568  $newContent = '!';
569  $mode = 'w';
570  $resource = $this->createResource($content, $mode);
571 
572  $subject = new Stream($resource);
573  $subject->detach();
574 
575  $this->expectException(\RuntimeException::class);
576  $this->expectExceptionMessage('Stream is detached');
577 
578  $subject->write($newContent);
579  }
580 
581  #[Test]
582 
584  {
585  $content = 'awesome content stream';
586  $newContent = '!';
587  $mode = 'r';
588  $resource = $this->createResource($content, $mode);
589 
590  $subject = new Stream($resource);
591 
592  $this->expectException(\RuntimeException::class);
593  $this->expectExceptionMessage('Can not write to a non-writable stream');
594 
595  $subject->write($newContent);
596  }
597 
598  #[Test]
599 
601  {
602  $content = 'awesome content stream';
603  $newContent = '!';
604  $mode = 'a+';
605  $resource = $this->createResource($content, $mode);
606 
607  $subject = new Stream($resource);
608 
609  //load mock class
610  $functionMock = Mockery::mock('alias:' . PHPStreamFunctions::class);
611 
612  $functionMock->shouldReceive('fwrite')
613  ->once()
614  ->withArgs([$resource, $newContent])
615  ->andReturn(false);
616 
617  $functionMock->shouldReceive('fclose')
618  ->once()
619  ->with($resource);
620 
621  $this->expectException(\RuntimeException::class);
622  $this->expectExceptionMessage('Unable to write to stream');
623 
624  $subject->write($newContent);
625  }
626 }
createResource(string $content, string $mode)
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.