1<?php
2
3/**
4 * Hoa
5 *
6 *
7 * @license
8 *
9 * New BSD License
10 *
11 * Copyright © 2007-2017, Hoa community. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *     * Redistributions of source code must retain the above copyright
16 *       notice, this list of conditions and the following disclaimer.
17 *     * Redistributions in binary form must reproduce the above copyright
18 *       notice, this list of conditions and the following disclaimer in the
19 *       documentation and/or other materials provided with the distribution.
20 *     * Neither the name of the Hoa nor the names of its contributors may be
21 *       used to endorse or promote products derived from this software without
22 *       specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37namespace Hoa\Protocol\Test\Unit;
38
39use Hoa\Protocol as LUT;
40use Hoa\Protocol\Wrapper as SUT;
41use Hoa\Test;
42
43/**
44 * Class \Hoa\Protocol\Test\Unit\Wrapper.
45 *
46 * Test suite of the stream wrapper.
47 *
48 * @copyright  Copyright © 2007-2017 Hoa community
49 * @license    New BSD License
50 */
51class Wrapper extends Test\Unit\Suite
52{
53    public function case_stream_cast_for_select()
54    {
55        $this
56            ->given($wrapper = new SUT())
57            ->when($result = $wrapper->stream_cast(STREAM_CAST_FOR_SELECT))
58            ->then
59                ->boolean($result)
60                    ->isFalse();
61    }
62
63    public function case_stream_cast_as_stream()
64    {
65        $this
66            ->given($wrapper = new SUT())
67            ->when($result = $wrapper->stream_cast(STREAM_CAST_AS_STREAM))
68            ->then
69                ->boolean($result)
70                    ->isFalse();
71    }
72
73    public function case_stream_close()
74    {
75        $this
76            ->given(
77                $wrapper = new SUT(),
78                $this->openFile($wrapper)
79            )
80            ->when($result = $wrapper->stream_close())
81            ->then
82                ->variable($result)
83                    ->isNull()
84                ->variable($wrapper->getStream())
85                    ->isNull()
86                ->variable($wrapper->getStreamName())
87                    ->isNull();
88    }
89
90    public function case_stream_not_eof()
91    {
92        $this
93            ->given(
94                $wrapper = new SUT(),
95                $this->openFile($wrapper, 'foo'),
96                fseek($wrapper->getStream(), 0, SEEK_SET)
97            )
98            ->when($result = $wrapper->stream_eof())
99            ->then
100                ->boolean($result)
101                    ->isFalse();
102    }
103
104    public function case_stream_eof()
105    {
106        $this
107            ->given(
108                $this->function->feof = true,
109                $wrapper = new SUT()
110            )
111            ->when($result = $wrapper->stream_eof())
112            ->then
113                ->boolean($result)
114                    ->isTrue();
115    }
116
117    public function case_stream_flush()
118    {
119        $this
120            ->given(
121                $wrapper = new SUT(),
122                $this->openFile($wrapper)
123            )
124            ->when($result = $wrapper->stream_flush())
125            ->then
126                ->boolean($result)
127                    ->isTrue();
128    }
129
130    public function _case_stream_xxx_lock($operation)
131    {
132        $this
133            ->given(
134                $this->function->flock = function ($resource, $operation) use (&$_resource, &$_operation) {
135                    $_resource  = $resource;
136                    $_operation = $operation;
137
138                    if ($operation === LOCK_NB) {
139                        return true;
140                    }
141
142                    return flock($resource, $operation);
143                },
144                $wrapper = new SUT(),
145                $this->openFile($wrapper)
146            )
147            ->when($result = $wrapper->stream_lock($operation))
148            ->then
149                ->boolean($result)
150                    ->isTrue()
151                ->resource($_resource)
152                    ->isStream()
153                    ->isIdenticalTo($wrapper->getStream())
154                ->integer($_operation)
155                    ->isEqualTo($operation);
156    }
157
158    public function case_stream_shared_lock()
159    {
160        return $this->_case_stream_xxx_lock(LOCK_SH);
161    }
162
163    public function case_stream_exclusive_lock()
164    {
165        return $this->_case_stream_xxx_lock(LOCK_EX);
166    }
167
168    public function case_stream_release_lock()
169    {
170        return $this->_case_stream_xxx_lock(LOCK_UN);
171    }
172
173    public function case_stream_not_blocking_lock()
174    {
175        return $this->_case_stream_xxx_lock(LOCK_NB);
176    }
177
178    public function _case_metadata_touch_with_xxx_arguments($arguments, $path, $time, $atime)
179    {
180        $this
181            ->given(
182                $this->function->touch = function ($path, $time, $atime) use (&$_path, &$_time, &$_atime) {
183                    $_path  = $path;
184                    $_time  = $time;
185                    $_atime = $atime;
186
187                    return true;
188                },
189                $wrapper = new SUT()
190            )
191            ->when($result = $wrapper->stream_metadata($path, STREAM_META_TOUCH, $arguments))
192            ->then
193                ->boolean($result)
194                    ->isTrue()
195                ->string($_path)
196                    ->isEqualTo($path)
197                ->variable($_time)
198                    ->isEqualTo($time)
199                ->variable($_atime)
200                    ->isEqualTo($atime);
201    }
202
203    public function case_metadata_touch_with_no_argument()
204    {
205        return $this->_case_metadata_touch_with_xxx_arguments([], 'foo', null, null);
206    }
207
208    public function case_metadata_touch_with_time()
209    {
210        return $this->_case_metadata_touch_with_xxx_arguments([42], 'foo', 42, null);
211    }
212
213    public function case_metadata_touch_with_time_and_atime()
214    {
215        return $this->_case_metadata_touch_with_xxx_arguments([42, 777], 'foo', 42, 777);
216    }
217
218    public function _case_metadata_owner_xxx($owner)
219    {
220        $this
221            ->given(
222                $this->function->chown = function ($path, $user) use (&$_path, &$_user) {
223                    $_path = $path;
224                    $_user = $user;
225
226                    return true;
227                },
228                $path    = 'foo',
229                $user    = 'gordon',
230                $wrapper = new SUT()
231            )
232            ->when($result = $wrapper->stream_metadata('foo', $owner, $user))
233            ->then
234                ->boolean($result)
235                    ->isTrue()
236                ->string($path)
237                    ->isEqualTo($_path)
238                ->string($user)
239                    ->isEqualTo($_user);
240    }
241
242    public function case_metadata_owner()
243    {
244        return $this->_case_metadata_owner_xxx(STREAM_META_OWNER);
245    }
246
247    public function case_metadata_owner_name()
248    {
249        return $this->_case_metadata_owner_xxx(STREAM_META_OWNER_NAME);
250    }
251
252    public function _case_metadata_group_xxx($grp)
253    {
254        $this
255            ->given(
256                $this->function->chgrp = function ($path, $group) use (&$_path, &$_group) {
257                    $_path  = $path;
258                    $_group = $group;
259
260                    return true;
261                },
262                $path    = 'foo',
263                $group   = 'root',
264                $wrapper = new SUT()
265            )
266            ->when($result = $wrapper->stream_metadata('foo', $grp, $group))
267            ->then
268                ->boolean($result)
269                    ->isTrue()
270                ->string($path)
271                    ->isEqualTo($_path)
272                ->string($group)
273                    ->isEqualTo($_group);
274    }
275
276    public function case_metadata_group()
277    {
278        return $this->_case_metadata_group_xxx(STREAM_META_GROUP);
279    }
280
281    public function case_metadata_group_name()
282    {
283        return $this->_case_metadata_group_xxx(STREAM_META_GROUP_NAME);
284    }
285
286    public function case_metadata_access()
287    {
288        $this
289            ->given(
290                $this->function->chmod = function ($path, $mode) use (&$_path, &$_mode) {
291                    $_path = $path;
292                    $_mode = $mode;
293
294                    return true;
295                },
296                $path    = 'foo',
297                $mode    = 0755,
298                $wrapper = new SUT()
299            )
300            ->when($result = $wrapper->stream_metadata('foo', STREAM_META_ACCESS, $mode))
301            ->then
302                ->boolean($result)
303                    ->isTrue()
304                ->string($path)
305                    ->isEqualTo($_path)
306                ->integer($mode)
307                    ->isEqualTo($_mode);
308    }
309
310    public function case_metadata_default()
311    {
312        $this
313            ->given(
314                $option  = 0,
315                $mode    = 0,
316                $wrapper = new SUT()
317            )
318            ->when($result = $wrapper->stream_metadata('foo', $option, $mode))
319            ->then
320                ->boolean($result)
321                    ->isFalse();
322    }
323
324    public function case_stream_open()
325    {
326        $this
327            ->given(
328                $this->function->fopen = function ($path, $mode, $options) use (&$_path, &$_mode, &$_options, &$_openedPath) {
329                    $_path    = $path;
330                    $_mode    = $mode;
331                    $_options = $options;
332
333                    return fopen($path, $mode, $options);
334                },
335                $wrapper = new SUT(),
336                $path    = 'hoa://Test/Vfs/Foo?type=file',
337                $mode    = 'r',
338                $options = STREAM_USE_PATH
339            )
340            ->when($result = $wrapper->stream_open($path, $mode, $options, $openedPath))
341            ->then
342                ->boolean($result)
343                    ->isTrue()
344                ->string(SUT::realPath($path, true))
345                    ->isEqualTo($_path)
346                ->string($mode)
347                    ->isEqualTo($_mode)
348                ->integer($options)
349                    ->isEqualTo($_options & STREAM_USE_PATH)
350                ->resource($openedPath)
351                    ->isStream()
352                    ->isIdenticalTo($wrapper->getStream())
353                ->string($wrapper->getStreamName())
354                    ->isEqualTo('atoum://Foo');
355    }
356
357    public function case_stream_open_not_hoa_protocol()
358    {
359        $this
360            ->given(
361                $wrapper = new SUT(),
362                $path    = LUT::NO_RESOLUTION,
363                $mode    = 'r',
364                $options = STREAM_USE_PATH
365            )
366            ->when($result = $wrapper->stream_open($path, $mode, $options, $openedPath))
367            ->then
368                ->boolean($result)
369                    ->isFalse();
370    }
371
372    public function case_stream_open_not_a_resource()
373    {
374        $this
375            ->given(
376                $this->function->fopen = function ($path, $mode, $options) use (&$_path, &$_mode, &$_options, &$_openedPath) {
377                    $_path    = $path;
378                    $_mode    = $mode;
379                    $_options = $options;
380
381                    return fopen($path, $mode, $options);
382                },
383                $this->function->is_resource = false,
384
385                $wrapper = new SUT(),
386                $path    = 'hoa://Test/Vfs/Foo?type=file',
387                $mode    = 'r',
388                $options = STREAM_USE_PATH
389            )
390            ->when($result = $wrapper->stream_open($path, $mode, $options, $openedPath))
391            ->then
392                ->boolean($result)
393                    ->isFalse()
394                ->string(SUT::realPath($path, true))
395                    ->isEqualTo($_path)
396                ->string($mode)
397                    ->isEqualTo($_mode)
398                ->integer($options)
399                    ->isEqualTo($_options & STREAM_USE_PATH)
400                ->resource($openedPath)
401                    ->isStream();
402    }
403
404    public function case_stream_read()
405    {
406        $this
407            ->given(
408                $this->function->fread = function ($resource, $count) use (&$_resource, &$_count) {
409                    $_resource = $resource;
410                    $_count    = $count;
411
412                    return fread($resource, $count);
413                },
414                $wrapper = new SUT(),
415                $count   = 42,
416                $this->openFile($wrapper, str_repeat('@', $count))
417            )
418            ->when($result = $wrapper->stream_read($count))
419            ->then
420                ->string($result)
421                    ->hasLength($count)
422                ->resource($_resource)
423                    ->isStream()
424                    ->isIdenticalTo($wrapper->getStream())
425                ->integer($_count)
426                    ->isEqualTo($count);
427    }
428
429    public function _case_stream_seek_xxx($offset, $whence)
430    {
431        return
432            $this
433                ->given(
434                    $this->function->fseek = function ($resource, $offset, $whence) use (&$_resource, &$_offset, &$_whence) {
435                        $_resource = $resource;
436                        $_offset   = $offset;
437                        $_whence   = $whence;
438
439                        return fseek($resource, $offset, $whence);
440                    },
441                    $wrapper = new SUT(),
442                    $this->openFile($wrapper, 'foobar')
443                )
444                ->when($result = $wrapper->stream_seek($offset, $whence))
445                ->then
446                    ->boolean($result)
447                        ->isTrue()
448                    ->resource($_resource)
449                        ->isStream()
450                        ->isIdenticalTo($wrapper->getStream())
451                    ->integer($offset)
452                        ->isEqualTo($_offset)
453                    ->integer($whence)
454                        ->isEqualTo($_whence)
455                    ->integer(ftell($wrapper->getStream()));
456    }
457
458    public function case_stream_seek_set()
459    {
460        return
461            $this
462                ->_case_stream_seek_xxx(3, SEEK_SET)
463                ->isEqualTo(3);
464    }
465
466    public function case_stream_seek_current()
467    {
468        return
469            $this
470                ->_case_stream_seek_xxx(4, SEEK_CUR)
471                ->isEqualTo(4);
472    }
473
474    public function case_stream_seek_end()
475    {
476        return
477            $this
478                ->_case_stream_seek_xxx(-4, SEEK_END)
479                ->isEqualTo(2);
480    }
481
482    public function case_stream_stat()
483    {
484        $this
485            ->given(
486                $this->function->fstat = function ($resource) use (&$_resource) {
487                    $_resource = $resource;
488
489                    return fstat($resource);
490                },
491                $wrapper = new SUT(),
492                $this->openFile($wrapper)
493            )
494            ->when($result = $wrapper->stream_stat())
495            ->then
496                ->array($result)
497                ->resource($_resource)
498                    ->isStream()
499                    ->isIdenticalTo($wrapper->getStream());
500    }
501
502    public function case_stream_tell()
503    {
504        $this
505            ->given(
506                $this->function->ftell = function ($resource) use (&$_resource) {
507                    $_resource = $resource;
508
509                    return ftell($resource);
510                },
511                $wrapper = new SUT(),
512                $this->openFile($wrapper, 'foo'),
513                $wrapper->stream_seek(2)
514            )
515            ->when($result = $wrapper->stream_tell())
516            ->then
517                ->integer($result)
518                    ->isEqualTo(2)
519                ->resource($_resource)
520                    ->isStream()
521                    ->isIdenticalTo($wrapper->getStream());
522    }
523
524    public function case_stream_truncate()
525    {
526        $this
527            ->given(
528                $this->function->ftruncate = function ($resource, $size) use (&$_resource, &$_size) {
529                    $_resource = $resource;
530                    $_size     = $size;
531
532                    return ftruncate($resource, $size);
533                },
534                $wrapper = new SUT(),
535                $this->openFile($wrapper, 'foobar'),
536                $size = 3
537            )
538            ->when($result = $wrapper->stream_truncate($size))
539            ->then
540                ->boolean($result)
541                    ->isTrue()
542                ->resource($_resource)
543                    ->isStream()
544                    ->isIdenticalTo($wrapper->getStream())
545                ->integer($size)
546                    ->isEqualTo($_size)
547                ->integer($wrapper->stream_tell())
548                    ->isEqualTo(0)
549                ->let($wrapper->stream_seek(0, SEEK_END))
550                ->integer($wrapper->stream_tell())
551                    ->isEqualTo(3);
552    }
553
554    public function case_stream_write()
555    {
556        $this
557            ->given(
558                $this->function->fwrite = function ($resource, $data) use (&$_resource, &$_data) {
559                    $_resource = $resource;
560                    $_data     = $data;
561
562                    return fwrite($resource, $data);
563                },
564                $wrapper = new SUT(),
565                $wrapper->stream_open('hoa://Test/Vfs/Foo?type=file', 'wb+', STREAM_USE_PATH, $openedPath),
566                $data = 'foo'
567            )
568            ->when($result = $wrapper->stream_write($data))
569            ->then
570                ->integer($result)
571                    ->isEqualTo(strlen($data))
572                ->resource($_resource)
573                    ->isStream()
574                    ->isIdenticalTo($wrapper->getStream())
575                ->string($_data)
576                    ->isEqualTo($data)
577                ->let($wrapper->stream_seek(0))
578                ->string($wrapper->stream_read(3))
579                    ->isEqualTo($data);
580    }
581
582    public function case_dir_closedir()
583    {
584        $this
585            ->given(
586                $wrapper = new SUT(),
587                $this->openDirectory($wrapper)
588            )
589            ->when($result = $wrapper->dir_closedir())
590            ->then
591                ->variable($result)
592                    ->isNull()
593                ->variable($wrapper->getStream())
594                    ->isNull()
595                ->variable($wrapper->getStreamName())
596                    ->isNull();
597    }
598
599    public function case_dir_opendir()
600    {
601        $this
602            ->given(
603                $this->function->opendir = function ($path) use (&$_path) {
604                    $_path = $path;
605
606                    return opendir($path);
607                },
608                $wrapper = new SUT(),
609                $path    = 'hoa://Test/Vfs/Bar?type=directory',
610                $options = 0
611            )
612            ->when($result = $wrapper->dir_opendir($path, $options))
613            ->then
614                ->boolean($result)
615                    ->isTrue()
616                ->string(SUT::realPath($path, true))
617                    ->isEqualTo($_path)
618                ->resource($wrapper->getStream())
619                    ->isStream()
620                ->string($wrapper->getStreamName())
621                    ->isEqualTo('atoum://Bar');
622    }
623
624    public function case_dir_opendir_not_a_resource()
625    {
626        $this
627            ->given(
628                $this->function->opendir = function ($path) use (&$_path) {
629                    $_path = $path;
630
631                    return false;
632                },
633                $wrapper = new SUT(),
634                $path    = 'hoa://Test/Vfs/Bar?type=directory',
635                $options = 0
636            )
637            ->when($result = $wrapper->dir_opendir($path, $options))
638            ->then
639                ->boolean($result)
640                    ->isFalse()
641                ->string(SUT::realPath($path, true))
642                    ->isEqualTo($_path)
643                ->variable($wrapper->getStream())
644                    ->isNull()
645                ->variable($wrapper->getStreamName())
646                    ->isNull();
647    }
648
649    public function case_dir_readdir()
650    {
651        $this
652            ->given(
653                $this->function->readdir = function ($resource) use (&$_resource) {
654                    $_resource = $resource;
655
656                    return readdir($resource);
657                },
658                $wrapper = new SUT(),
659                $this->openDirectory($wrapper, ['Baz', 'Qux'])
660            )
661            ->when($result = $wrapper->dir_readdir())
662            ->then
663                ->string($result)
664                    ->isEqualTo('Baz')
665                ->resource($_resource)
666                    ->isIdenticalTo($wrapper->getStream());
667    }
668
669    public function case_dir_readdir_until_eod()
670    {
671        $this
672            ->given(
673                $this->function->readdir = function ($resource) use (&$_resource) {
674                    $_resource = $resource;
675
676                    return readdir($resource);
677                },
678                $wrapper = new SUT(),
679                $this->openDirectory($wrapper, ['Baz', 'Qux'])
680            )
681            ->when($result = $wrapper->dir_readdir())
682            ->then
683                ->string($result)
684                    ->isEqualTo('Baz')
685                ->resource($_resource)
686                    ->isIdenticalTo($wrapper->getStream())
687
688            ->when($result = $wrapper->dir_readdir())
689            ->then
690                ->string($result)
691                    ->isEqualTo('Qux')
692
693            ->when($result = $wrapper->dir_readdir())
694            ->then
695                ->boolean($result)
696                    ->isFalse();
697    }
698
699    public function case_dir_rewinddir()
700    {
701        $this
702            ->given(
703                $this->function->rewinddir = function ($resource) use (&$_resource) {
704                    $_resource = $resource;
705
706                    return rewinddir($resource);
707                },
708                $wrapper = new SUT(),
709                $this->openDirectory($wrapper, ['Baz']),
710                $wrapper->dir_readdir()
711            )
712            ->when($result = $wrapper->dir_rewinddir())
713            ->then
714                ->variable($result)
715                    ->isNull()
716
717            ->when($result = $wrapper->dir_readdir())
718            ->then
719                ->string($result)
720                    ->isEqualTo('Baz')
721                ->resource($_resource)
722                    ->isIdenticalTo($wrapper->getStream());
723    }
724
725    public function case_dir_mkdir()
726    {
727        $this
728            ->given(
729                $this->function->mkdir = function ($path, $mode, $options) use (&$_path, &$_mode, &$_options) {
730                    $_path    = $path;
731                    $_mode    = $mode;
732                    $_options = $options;
733
734                    return true;
735                },
736                $wrapper = new SUT(),
737                $this->openDirectory($wrapper),
738                $path    = 'Baz',
739                $mode    = 0755,
740                $options = STREAM_MKDIR_RECURSIVE
741            )
742            ->when($result = $wrapper->mkdir($path, $mode, $options))
743            ->then
744                ->boolean($result)
745                    ->isTrue()
746                ->string($_path)
747                    ->isEqualTo($path)
748                ->integer($_mode)
749                    ->isEqualTo($_mode)
750                ->integer($_options)
751                    ->isEqualTo($options | STREAM_MKDIR_RECURSIVE);
752    }
753
754    public function case_rename()
755    {
756        $this
757            ->given(
758                $this->function->rename = function ($from, $to) use (&$_from, &$_to) {
759                    $_to   = $to;
760                    $_from = $from;
761
762                    return rename($from, $to);
763                },
764                $wrapper = new SUT(),
765                $this->openFile($wrapper),
766                $from    = 'hoa://Test/Vfs/Foo?type=file',
767                $to      = 'hoa://Test/Vfs/Oof?type=file'
768            )
769            ->when($result = $wrapper->rename($from, $to))
770            ->then
771                ->boolean($result)
772                    ->isTrue()
773                ->string($_from)
774                    ->isEqualTo(SUT::realPath($from))
775                ->string($_to)
776                    ->isEqualTo(SUT::realPath($_to, false));
777    }
778
779    public function case_rmdir()
780    {
781        $this
782            ->given(
783                $this->function->rmdir = function ($path) use (&$_path) {
784                    $_path = $path;
785
786                    return rmdir($path);
787                },
788                $wrapper = new SUT(),
789                $this->openDirectory($wrapper)
790            )
791            ->when($result = $wrapper->rmdir('hoa://Test/Vfs/Bar?type=directory', 0))
792            ->then
793                ->boolean($result)
794                    ->isTrue();
795    }
796
797    public function case_rmdir_a_file()
798    {
799        $this
800            ->given(
801                $wrapper = new SUT(),
802                $this->openFile($wrapper)
803            )
804            ->when($result = $wrapper->rmdir('hoa://Test/Vfs/Foo?type=file', 0))
805            ->then
806                ->boolean($result)
807                    ->isFalse();
808    }
809
810    public function case_unlink()
811    {
812        $this
813            ->given(
814                $wrapper = new SUT(),
815                $this->openFile($wrapper)
816            )
817            ->when($result = $wrapper->unlink('hoa://Test/Vfs/Foo?type=file'))
818            ->then
819                ->boolean($result)
820                    ->isTrue();
821    }
822
823    public function case_rmdir_a_directory()
824    {
825        $this
826            ->given(
827                $wrapper = new SUT(),
828                $this->openDirectory($wrapper)
829            )
830            ->when($result = $wrapper->unlink('hoa://Test/Vfs/Bar?type=directory'))
831            ->then
832                ->boolean($result)
833                    ->isFalse();
834    }
835
836    public function case_url_stat()
837    {
838        $this
839            ->given(
840                $this->function->stat = function ($path) use (&$_path) {
841                    $_path = $path;
842
843                    return stat($path);
844                },
845                $wrapper = new SUT(),
846                $this->openFile($wrapper),
847                $path = 'hoa://Test/Vfs/Foo?type=file'
848            )
849            ->when($result = $wrapper->url_stat($path, 0))
850            ->then
851                ->let(
852                    $keys = [
853                        'dev',
854                        'ino',
855                        'mode',
856                        'nlink',
857                        'uid',
858                        'gid',
859                        'rdev',
860                        'size',
861                        'atime',
862                        'mtime',
863                        'ctime',
864                        'blksize',
865                        'blocks'
866                    ]
867                )
868                ->array($result)
869                    ->hasSize(26)
870                    ->hasKeys($keys)
871                    ->hasKeys(array_keys($keys))
872                ->string($_path)
873                    ->isEqualTo(SUT::realPath($path));
874    }
875
876    public function case_url_stat_not_hoa_protocol()
877    {
878        $this
879            ->given(
880                $wrapper = new SUT(),
881                $path    = LUT::NO_RESOLUTION
882            )
883            ->when(function () use ($wrapper, $path) {
884                $wrapper->url_stat($path, 0);
885            })
886            ->then
887                ->error()
888                    ->exists();
889    }
890
891    protected function openFile(SUT $wrapper, $content = '')
892    {
893        $wrapper->stream_open('hoa://Test/Vfs/Foo?type=file', 'wb+', STREAM_USE_PATH, $openedPath);
894        fwrite($openedPath, $content, strlen($content));
895        fseek($openedPath, 0, SEEK_SET);
896
897        return $wrapper;
898    }
899
900    protected function openDirectory(SUT $wrapper, array $children = [])
901    {
902        $wrapper->dir_opendir('hoa://Test/Vfs/Bar?type=directory', 0);
903
904        foreach ($children as $child) {
905            resolve('hoa://Test/Vfs/Bar/' . $child . '?type=file');
906        }
907
908        return $wrapper;
909    }
910}
911