Passed
Push — develop ( 96496e...268024 )
by nguereza
01:39
created

PlatineTestCase   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 258
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 24
eloc 60
c 1
b 0
f 0
dl 0
loc 258
rs 10

15 Methods

Rating   Name   Duplication   Size   Complexity  
A getClassMethodsToMock() 0 19 5
A getPropertyValue() 0 4 1
A assertCommandOutput() 0 4 1
A getMockInstanceMap() 0 21 2
A setPropertyValue() 0 4 1
A getMockInstance() 0 19 2
A createVfsFileOnly() 0 6 1
A createFile() 0 3 1
A createVfsDirectory() 0 8 2
A enableFileSystem() 0 5 1
A getPrivateProtectedAttribute() 0 7 1
A tearDown() 0 6 3
A runPrivateProtectedMethod() 0 9 1
A createDirectory() 0 3 1
A createVfsFile() 0 8 1
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
     * Enable support of virtual file system
75
     * @return $this
76
     */
77
    public function enableFileSystem(): self
78
    {
79
        $this->fs = new PlatineFileSystem();
80
81
        return $this;
82
    }
83
84
    /**
85
     * Method to test private & protected method
86
     *
87
     * @param object $object the class instance to use
88
     * @param string $method the name of the method
89
     * @param array<int, mixed> $args the list of method arguments
90
     * @return mixed
91
     */
92
    public function runPrivateProtectedMethod(
93
        object $object,
94
        string $method,
95
        array $args = []
96
    ) {
97
        $reflection = new ReflectionClass(get_class($object));
98
        $reflectionMethod = $reflection->getMethod($method);
99
        $reflectionMethod->setAccessible(true);
100
        return $reflectionMethod->invokeArgs($object, $args);
101
    }
102
103
    /**
104
     * Method to set/get private & protected attribute
105
     *
106
     * @param string $className the name of the class
107
     * @param string $attr the name of the class attribute
108
     */
109
    public function getPrivateProtectedAttribute(
110
        string $className,
111
        string $attr
112
    ): ReflectionProperty {
113
        $rProp = new ReflectionProperty($className, $attr);
114
        $rProp->setAccessible(true);
115
        return $rProp;
116
    }
117
118
    /**
119
     * Create virtual file with the given content
120
     * @param  string $filename
121
     * @param  vfsStreamContainer<vfsStreamContainerIterator> $destination
122
     * @param  string $content
123
     * @return vfsStreamFile
124
     */
125
    public function createVfsFile(
126
        string $filename,
127
        vfsStreamContainer $destination,
128
        string $content = ''
129
    ): vfsStreamFile {
130
        return vfsStream::newFile($filename)
131
                        ->at($destination)
132
                        ->setContent($content);
133
    }
134
135
    /**
136
     * Create virtual file without content
137
     * @param  string $filename
138
     * @param  vfsStreamContainer<vfsStreamContainerIterator> $destination
139
     * @return vfsStreamFile
140
     */
141
    public function createVfsFileOnly(
142
        string $filename,
143
        vfsStreamContainer $destination
144
    ): vfsStreamFile {
145
        return vfsStream::newFile($filename)
146
                        ->at($destination);
147
    }
148
149
    /**
150
     * Create virtual directory
151
     * @param  string $name
152
     * @param  vfsStreamContainer<vfsStreamContainerIterator> $destination
153
     * @return vfsStreamDirectory
154
     */
155
    public function createVfsDirectory(
156
        string $name,
157
        vfsStreamContainer $destination = null
158
    ): vfsStreamDirectory {
159
        if ($destination) {
160
            return vfsStream::newDirectory($name)->at($destination);
161
        }
162
        return vfsStream::newDirectory($name);
163
    }
164
165
    /**
166
     * Create new virtual file
167
     * @param string $filename
168
     * @param string|null $content
169
     * @return File
170
     */
171
    public function createFile(string $filename, ?string $content = null): File
172
    {
173
        return $this->fs->createFile($filename, $content);
174
    }
175
176
    /**
177
     * Create new virtual directory
178
     * @param string $path
179
     * @param bool $recursive
180
     * @param int|null $mode
181
     * @return Directory
182
     */
183
    public function createDirectory(string $path, bool $recursive = false, ?int $mode = null): Directory
184
    {
185
        return $this->fs->createDirectory($path, $recursive, $mode);
186
    }
187
188
    /**
189
     * Return the list of methods to mocks in the parameters of PHPUnit::TestCase::getMock()
190
     *
191
     * @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...
192
     * @param string[] $exclude list of methods to exclude
193
     * @return string[]
194
     */
195
    public function getClassMethodsToMock($class, array $exclude = []): array
196
    {
197
        $methods = [];
198
199
        if (is_string($class) && !class_exists($class)) {
200
            throw new InvalidArgumentException(
201
                sprintf('Can not find class [%s]', $class)
202
            );
203
        }
204
205
        $reflectionClass = new ReflectionClass($class);
206
207
        foreach ($reflectionClass->getMethods() as $reflectionMethod) {
208
            if (!in_array($reflectionMethod->name, $exclude)) {
209
                $methods[] = $reflectionMethod->name;
210
            }
211
        }
212
213
        return $methods;
214
    }
215
216
    /**
217
     * Get the instance of the given class
218
     * @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...
219
     * @param array<string, mixed> $mockMethods
220
     * @param array<int, string> $excludes
221
     * @return mixed
222
     */
223
    public function getMockInstance(
224
        string $class,
225
        array $mockMethods = [],
226
        array $excludes = []
227
    ) {
228
        $methods = $this->getClassMethodsToMock($class, $excludes);
229
230
        $mock = $this->getMockBuilder($class)
231
                    ->disableOriginalConstructor()
232
                    ->onlyMethods($methods)
233
                    ->getMock();
234
235
        foreach ($mockMethods as $method => $returnValue) {
236
            $mock->expects($this->any())
237
                ->method($method)
238
                ->will($this->returnValue($returnValue));
239
        }
240
241
        return $mock;
242
    }
243
244
    /**
245
     * Get the instance of the given class using return map
246
     * @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...
247
     * @param array<string, mixed> $mockMethods
248
     * @param array<int, string> $excludes
249
     * @return mixed
250
     */
251
    public function getMockInstanceMap(
252
        string $class,
253
        array $mockMethods = [],
254
        array $excludes = []
255
    ) {
256
        $methods = $this->getClassMethodsToMock($class, $excludes);
257
258
        $mock = $this->getMockBuilder($class)
259
                    ->disableOriginalConstructor()
260
                    ->onlyMethods($methods)
261
                    ->getMock();
262
263
        foreach ($mockMethods as $method => $returnValues) {
264
            $mock->expects($this->any())
265
                ->method($method)
266
                ->will(
267
                    $this->returnValueMap($returnValues)
268
                );
269
        }
270
271
        return $mock;
272
    }
273
274
    /**
275
     * Return the value of private or protected property
276
     * @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...
277
     * @param object $instance
278
     * @param string $name
279
     * @return mixed
280
     */
281
    public function getPropertyValue(string $class, object $instance, string $name)
282
    {
283
        $reflection = $this->getPrivateProtectedAttribute($class, $name);
284
        return $reflection->getValue($instance);
285
    }
286
287
    /**
288
     * Set the value of private or protected property
289
     * @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...
290
     * @param object $instance
291
     * @param string $name
292
     * @param mixed $value
293
     * @return void
294
     */
295
    public function setPropertyValue(string $class, object $instance, string $name, $value)
296
    {
297
        $reflection = $this->getPrivateProtectedAttribute($class, $name);
298
        $reflection->setValue($instance, $value);
299
    }
300
301
    /**
302
     * Test assert command expected given output
303
     * @param string $expected
304
     * @param string $output
305
     * @return void
306
     */
307
    public function assertCommandOutput(string $expected, string $output): void
308
    {
309
        $result = str_replace("\n", PHP_EOL, $expected);
310
        $this->assertEquals($result, $output);
311
    }
312
313
    /**
314
     * @codeCoverageIgnore
315
     * @return void
316
     */
317
    protected function tearDown(): void
318
    {
319
        //restore all mock variable global value to "false"
320
        foreach ($GLOBALS as $key => $value) {
321
            if (substr((string) $key, 0, 5) === 'mock_') {
322
                $GLOBALS[$key] = false;
323
            }
324
        }
325
    }
326
}
327