Passed
Push — develop ( bb6909...96496e )
by nguereza
01:35
created

PlatineTestCase::getPlatineFileSystem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * Platine Dev Tools
5
 *
6
 * Platine Dev Tools is a collection of some classes/functions
7
 * designed for development
8
 *
9
 * This content is released under the MIT License (MIT)
10
 *
11
 * Copyright (c) 2020 Platine Dev Tools
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy
14
 * of this software and associated documentation files (the "Software"), to deal
15
 * in the Software without restriction, including without limitation the rights
16
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
 * copies of the Software, and to permit persons to whom the Software is
18
 * furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all
21
 * copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
 * SOFTWARE.
30
 */
31
32
/**
33
 *  @file PlatineTestCase.php
34
 *
35
 *  The Base class used for test case
36
 *
37
 *  @package    Platine\Dev
38
 *  @author Platine Developers Team
39
 *  @copyright  Copyright (c) 2020
40
 *  @license    http://opensource.org/licenses/MIT  MIT License
41
 *  @link   https://www.platine-php.com
42
 *  @version 1.0.0
43
 *  @filesource
44
 */
45
46
declare(strict_types=1);
47
48
namespace Platine\Dev;
49
50
use InvalidArgumentException;
51
use org\bovigo\vfs\vfsStream;
52
use org\bovigo\vfs\vfsStreamContainer;
53
use org\bovigo\vfs\vfsStreamDirectory;
54
use org\bovigo\vfs\vfsStreamFile;
55
use PHPUnit\Framework\TestCase;
56
use ReflectionClass;
57
use ReflectionProperty;
58
use VirtualFileSystem\Structure\Directory;
59
use VirtualFileSystem\Structure\File;
60
61
/**
62
 * @class PlatineTestCase
63
 * @package Platine\Dev
64
 */
65
class PlatineTestCase extends TestCase
66
{
67
    /**
68
     * The Platine File system instance
69
     * @var PlatineFileSystem
70
     */
71
    protected PlatineFileSystem $fs;
72
73
    /**
74
     * Return the virtual file system
75
     * @return PlatineFileSystem
76
     */
77
    public function getPlatineFileSystem(): PlatineFileSystem
78
    {
79
        return $this->fs;
80
    }
81
82
    /**
83
     * Set the virtual file system
84
     * @param PlatineFileSystem $fs
85
     * @return $this
86
     */
87
    public function setPlatineFileSystem(PlatineFileSystem $fs): self
88
    {
89
        $this->fs = $fs;
90
        return $this;
91
    }
92
93
94
95
    /**
96
     * Method to test private & protected method
97
     *
98
     * @param object $object the class instance to use
99
     * @param string $method the name of the method
100
     * @param array<int, mixed> $args the list of method arguments
101
     * @return mixed
102
     */
103
    public function runPrivateProtectedMethod(
104
        object $object,
105
        string $method,
106
        array $args = []
107
    ) {
108
        $reflection = new ReflectionClass(get_class($object));
109
        $reflectionMethod = $reflection->getMethod($method);
110
        $reflectionMethod->setAccessible(true);
111
        return $reflectionMethod->invokeArgs($object, $args);
112
    }
113
114
    /**
115
     * Method to set/get private & protected attribute
116
     *
117
     * @param string $className the name of the class
118
     * @param string $attr the name of the class attribute
119
     */
120
    public function getPrivateProtectedAttribute(
121
        string $className,
122
        string $attr
123
    ): ReflectionProperty {
124
        $rProp = new ReflectionProperty($className, $attr);
125
        $rProp->setAccessible(true);
126
        return $rProp;
127
    }
128
129
    /**
130
     * Create virtual file with the given content
131
     * @param  string $filename
132
     * @param  vfsStreamContainer<vfsStreamContainerIterator> $destination
133
     * @param  string $content
134
     * @return vfsStreamFile
135
     */
136
    public function createVfsFile(
137
        string $filename,
138
        vfsStreamContainer $destination,
139
        string $content = ''
140
    ): vfsStreamFile {
141
        return vfsStream::newFile($filename)
142
                        ->at($destination)
143
                        ->setContent($content);
144
    }
145
146
    /**
147
     * Create virtual file without content
148
     * @param  string $filename
149
     * @param  vfsStreamContainer<vfsStreamContainerIterator> $destination
150
     * @return vfsStreamFile
151
     */
152
    public function createVfsFileOnly(
153
        string $filename,
154
        vfsStreamContainer $destination
155
    ): vfsStreamFile {
156
        return vfsStream::newFile($filename)
157
                        ->at($destination);
158
    }
159
160
    /**
161
     * Create virtual directory
162
     * @param  string $name
163
     * @param  vfsStreamContainer<vfsStreamContainerIterator> $destination
164
     * @return vfsStreamDirectory
165
     */
166
    public function createVfsDirectory(
167
        string $name,
168
        vfsStreamContainer $destination = null
169
    ): vfsStreamDirectory {
170
        if ($destination) {
171
            return vfsStream::newDirectory($name)->at($destination);
172
        }
173
        return vfsStream::newDirectory($name);
174
    }
175
176
    /**
177
     * Create new virtual file
178
     * @param string $filename
179
     * @param string|null $content
180
     * @return File
181
     */
182
    public function createFile(string $filename, ?string $content = null): File
183
    {
184
        return $this->fs->createFile($filename, $content);
185
    }
186
187
    /**
188
     * Create new virtual directory
189
     * @param string $path
190
     * @param bool $recursive
191
     * @param int|null $mode
192
     * @return Directory
193
     */
194
    public function createDirectory(string $path, bool $recursive = false, ?int $mode = null): Directory
195
    {
196
        return $this->fs->createDirectory($path, $recursive, $mode);
197
    }
198
199
    /**
200
     * Return the list of methods to mocks in the parameters of PHPUnit::TestCase::getMock()
201
     *
202
     * @param class-string<object>|object $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<object>|object at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<object>|object.
Loading history...
203
     * @param string[] $exclude list of methods to exclude
204
     * @return string[]
205
     */
206
    public function getClassMethodsToMock($class, array $exclude = []): array
207
    {
208
        $methods = [];
209
210
        if (is_string($class) && !class_exists($class)) {
211
            throw new InvalidArgumentException(
212
                sprintf('Can not find class [%s]', $class)
213
            );
214
        }
215
216
        $reflectionClass = new ReflectionClass($class);
217
218
        foreach ($reflectionClass->getMethods() as $reflectionMethod) {
219
            if (!in_array($reflectionMethod->name, $exclude)) {
220
                $methods[] = $reflectionMethod->name;
221
            }
222
        }
223
224
        return $methods;
225
    }
226
227
    /**
228
     * Get the instance of the given class
229
     * @param class-string $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
230
     * @param array<string, mixed> $mockMethods
231
     * @param array<int, string> $excludes
232
     * @return mixed
233
     */
234
    public function getMockInstance(
235
        string $class,
236
        array $mockMethods = [],
237
        array $excludes = []
238
    ) {
239
        $methods = $this->getClassMethodsToMock($class, $excludes);
240
241
        $mock = $this->getMockBuilder($class)
242
                    ->disableOriginalConstructor()
243
                    ->onlyMethods($methods)
244
                    ->getMock();
245
246
        foreach ($mockMethods as $method => $returnValue) {
247
            $mock->expects($this->any())
248
                ->method($method)
249
                ->will($this->returnValue($returnValue));
250
        }
251
252
        return $mock;
253
    }
254
255
    /**
256
     * Get the instance of the given class using return map
257
     * @param class-string $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
258
     * @param array<string, mixed> $mockMethods
259
     * @param array<int, string> $excludes
260
     * @return mixed
261
     */
262
    public function getMockInstanceMap(
263
        string $class,
264
        array $mockMethods = [],
265
        array $excludes = []
266
    ) {
267
        $methods = $this->getClassMethodsToMock($class, $excludes);
268
269
        $mock = $this->getMockBuilder($class)
270
                    ->disableOriginalConstructor()
271
                    ->onlyMethods($methods)
272
                    ->getMock();
273
274
        foreach ($mockMethods as $method => $returnValues) {
275
            $mock->expects($this->any())
276
                ->method($method)
277
                ->will(
278
                    $this->returnValueMap($returnValues)
279
                );
280
        }
281
282
        return $mock;
283
    }
284
285
    /**
286
     * Return the value of private or protected property
287
     * @param class-string $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
288
     * @param object $instance
289
     * @param string $name
290
     * @return mixed
291
     */
292
    public function getPropertyValue(string $class, object $instance, string $name)
293
    {
294
        $reflection = $this->getPrivateProtectedAttribute($class, $name);
295
        return $reflection->getValue($instance);
296
    }
297
298
    /**
299
     * Set the value of private or protected property
300
     * @param class-string $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
301
     * @param object $instance
302
     * @param string $name
303
     * @param mixed $value
304
     * @return void
305
     */
306
    public function setPropertyValue(string $class, object $instance, string $name, $value)
307
    {
308
        $reflection = $this->getPrivateProtectedAttribute($class, $name);
309
        $reflection->setValue($instance, $value);
310
    }
311
312
    /**
313
     * Test assert command expected given output
314
     * @param string $expected
315
     * @param string $output
316
     * @return void
317
     */
318
    public function assertCommandOutput(string $expected, string $output): void
319
    {
320
        $result = str_replace("\n", PHP_EOL, $expected);
321
        $this->assertEquals($result, $output);
322
    }
323
324
    /**
325
     * @codeCoverageIgnore
326
     * @return void
327
     */
328
    protected function tearDown(): void
329
    {
330
        //restore all mock variable global value to "false"
331
        foreach ($GLOBALS as $key => $value) {
332
            if (substr((string) $key, 0, 5) === 'mock_') {
333
                $GLOBALS[$key] = false;
334
            }
335
        }
336
    }
337
}
338