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 
37 namespace Hoa\Protocol\Test\Unit;
38 
39 use Hoa\Protocol as LUT;
40 use Hoa\Protocol\Wrapper as SUT;
41 use 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  */
51 class 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