Passed
Push — v7 ( ef6b54...43ee37 )
by Georges
01:54
created

TestHelper::getExitCode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 *
4
 * This file is part of phpFastCache.
5
 *
6
 * @license MIT License (MIT)
7
 *
8
 * For full copyright and license information, please see the docs/CREDITS.txt file.
9
 *
10
 * @author Khoa Bui (khoaofgod)  <[email protected]> http://www.phpfastcache.com
11
 * @author Georges.L (Geolim4)  <[email protected]>
12
 *
13
 */
14
declare(strict_types=1);
15
16
namespace Phpfastcache\Helper;
17
18
use Phpfastcache\Api;
19
use Phpfastcache\Exceptions\PhpfastcacheDriverCheckException;
20
21
/**
22
 * Class TestHelper
23
 * @package phpFastCache\Helper
24
 */
25
class TestHelper
26
{
27
    /**
28
     * @var string
29
     */
30
    protected $testName;
31
32
    /**
33
     * @var int
34
     */
35
    protected $exitCode = 0;
36
37
    /**
38
     * @var int
39
     */
40
    protected $timestamp;
41
42
    /**
43
     * TestHelper constructor.
44
     *
45
     * @param string $testName
46
     * @throws \Phpfastcache\Exceptions\PhpfastcacheIOException
47
     * @throws \Phpfastcache\Exceptions\PhpfastcacheLogicException
48
     */
49
    public function __construct(string $testName)
50
    {
51
        $this->timestamp = microtime(true);
52
        $this->testName = $testName;
53
54
        /**
55
         * Catch all uncaught exception
56
         * to our own exception handler
57
         */
58
        set_exception_handler([$this, 'exceptionHandler']);
59
        set_error_handler([$this, 'errorHandler']);
60
61
        $this->printHeaders();
62
    }
63
64
    /**
65
     * @throws \Phpfastcache\Exceptions\PhpfastcacheIOException
66
     * @throws \Phpfastcache\Exceptions\PhpfastcacheLogicException
67
     */
68
    public function printHeaders()
69
    {
70
        if(!$this->isCli() && !\headers_sent()){
71
            \header('Content-Type: text/plain, true');
72
        }
73
74
        $this->printText('[PhpFastCache CORE v' . Api::getPhpFastCacheVersion() . Api::getPhpFastCacheGitHeadHash() . ']', true);
75
        $this->printText('[PhpFastCache API v' . Api::getVersion() . ']', true);
76
        $this->printText('[PHP v' . PHP_VERSION . ']', true);
77
        $this->printText("[Begin Test: '{$this->testName}']");
78
        $this->printText('---');
79
80
    }
81
82
    /**
83
     * @return int
84
     */
85
    public function getExitCode(): int
86
    {
87
        return $this->exitCode;
88
    }
89
90
    /**
91
     * @return $this
92
     */
93
    public function resetExitCode(): self
94
    {
95
        $this->exitCode = 0;
96
97
        return $this;
98
    }
99
100
    /**
101
     * @param string $string
102
     * @return $this
103
     */
104
    public function printSkipText(string $string): self
105
    {
106
        $this->printText($string, false, 'SKIP');
107
108
        return $this;
109
    }
110
111
    /**
112
     * @param string $string
113
     * @return $this
114
     */
115
    public function printPassText(string $string): self
116
    {
117
        $this->printText($string, false, 'PASS');
118
119
120
        return $this;
121
    }
122
123
    /**
124
     * @param string printFailText
0 ignored issues
show
Bug introduced by
The type Phpfastcache\Helper\printFailText was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
125
     * @return $this
126
     */
127
    public function printInfoText(string $string): self
128
    {
129
        $this->printText($string, false, 'INFO');
130
131
132
        return $this;
133
    }
134
135
    /**
136
     * @param string $string
137
     * @return $this
138
     */
139
    public function printDebugText(string $string): self
140
    {
141
        $this->printText($string, false, 'DEBUG');
142
143
        return $this;
144
    }
145
146
    /**
147
     * @param string $string
148
     * @return $this
149
     */
150
    public function printNoteText(string $string): self
151
    {
152
        $this->printText($string, false, 'NOTE');
153
154
        return $this;
155
    }
156
157
    /**
158
     * @param string $string
159
     * @return $this
160
     */
161
    public function printFailText(string $string): self
162
    {
163
        $this->printText($string, false, 'FAIL');
164
        $this->exitCode = 1;
165
166
        return $this;
167
    }
168
169
    /**
170
     * @param int $count
171
     * @return $this
172
     */
173
    public function printNewLine(int $count = 1): self
174
    {
175
        print \str_repeat(PHP_EOL, $count);
176
        return $this;
177
    }
178
179
    /**
180
     * @param string $string
181
     * @param bool $strtoupper
182
     * @param string $prefix
183
     * @return $this
184
     */
185
    public function printText(string $string, bool $strtoupper = false, string $prefix = ''): self
186
    {
187
        if ($prefix) {
188
            $string = "[{$prefix}] {$string}";
189
        }
190
        if (!$strtoupper) {
191
            print \trim($string) . PHP_EOL;
192
        } else {
193
            print \strtoupper(\trim($string) . PHP_EOL);
194
        }
195
196
        return $this;
197
    }
198
199
    /**
200
     * @param string $cmd
201
     */
202
    public function runAsyncProcess(string $cmd)
203
    {
204
        if (\substr(\php_uname(), 0, 7) === 'Windows') {
205
            \pclose(\popen('start /B ' . $cmd, 'r'));
0 ignored issues
show
Bug introduced by
It seems like popen('start /B ' . $cmd, 'r') can also be of type false; however, parameter $handle of pclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

205
            \pclose(/** @scrutinizer ignore-type */ \popen('start /B ' . $cmd, 'r'));
Loading history...
206
        } else {
207
            \exec($cmd . ' > /dev/null &');
208
        }
209
    }
210
211
    /**
212
     * @param string $file
213
     * @param string $ext
214
     */
215
    public function runSubProcess(string $file, string $ext = '.php')
216
    {
217
        $this->runAsyncProcess(($this->isHHVM() ? 'hhvm ' : 'php ') . \getcwd() . \DIRECTORY_SEPARATOR . 'subprocess' . \DIRECTORY_SEPARATOR . $file . '.subprocess' . $ext);
218
    }
219
220
    /**
221
     * @return void
222
     */
223
    public function terminateTest()
224
    {
225
        $execTime = \round(\microtime(true) - $this->timestamp, 3);
226
227
        $this->printText('Test finished in ' . $execTime . 's');
228
        exit($this->exitCode);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
229
    }
230
231
    /**
232
     * @return bool
233
     */
234
    public function isHHVM(): bool
235
    {
236
        return \defined('HHVM_VERSION');
237
    }
238
239
    /**
240
     * @param $obj
241
     * @param $prop
242
     * @return mixed
243
     * @throws \ReflectionException
244
     */
245
    public function accessInaccessibleMember($obj, $prop)
246
    {
247
        $reflection = new \ReflectionClass($obj);
248
        $property = $reflection->getProperty($prop);
249
        $property->setAccessible(true);
250
        return $property->getValue($obj);
251
    }
252
253
    /**
254
     * @param \Throwable $exception
255
     */
256
    public function exceptionHandler(\Throwable $exception)
257
    {
258
        if ($exception instanceof PhpfastcacheDriverCheckException) {
259
            $this->printSkipText('A driver could not be initialized due to missing requirement: ' . $exception->getMessage());
260
        } else {
261
            $this->printFailText(\sprintf(
262
              'Uncaught exception "%s" in "%s" line %d with message: "%s"',
263
              \get_class($exception),
264
              $exception->getFile(),
265
              $exception->getLine(),
266
              $exception->getMessage()
267
            ));
268
        }
269
        $this->terminateTest();
270
    }
271
272
    /**
273
     * @param int $errno
274
     * @param string $errstr
275
     * @param string $errfile
276
     * @param int $errline
277
     */
278
    public function errorHandler(int $errno, string $errstr, string $errfile, int $errline)
279
    {
280
        $errorType = '';
281
282
        switch ($errno) {
283
            case E_PARSE:
284
            case E_ERROR:
285
            case E_CORE_ERROR:
286
            case E_COMPILE_ERROR:
287
            case E_USER_ERROR:
288
                $errorType = '[FATAL ERROR]';
289
                break;
290
            case E_WARNING:
291
            case E_USER_WARNING:
292
            case E_COMPILE_WARNING:
293
            case E_RECOVERABLE_ERROR:
294
                $errorType = '[WARNING]';
295
                break;
296
            case E_NOTICE:
297
            case E_USER_NOTICE:
298
                $errorType = '[NOTICE]';
299
                break;
300
            case E_STRICT:
301
                $errorType = '[STRICT]';
302
                break;
303
            case E_DEPRECATED:
304
            case E_USER_DEPRECATED:
305
                $errorType = '[DEPRECATED]';
306
                break;
307
            default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
308
                break;
309
        }
310
311
        if ($errorType === '[FATAL ERROR]') {
312
            $this->printFailText(\sprintf(
313
              "A critical error has been caught: \"%s\" in %s line %d",
314
              "$errorType $errstr",
315
              $errfile,
316
              $errline
317
            ));
318
        } else {
319
            $this->printDebugText(\sprintf(
320
              "A non-critical error has been caught: \"%s\" in %s line %d",
321
              "$errorType $errstr",
322
              $errfile,
323
              $errline
324
            ));
325
        }
326
    }
327
328
    /**
329
     * @see https://stackoverflow.com/questions/933367/php-how-to-best-determine-if-the-current-invocation-is-from-cli-or-web-server
330
     * @return bool
331
     */
332
    public function isCli(): bool
333
    {
334
        if (\defined('STDIN')) {
335
            return true;
336
        }
337
338
        if (\php_sapi_name() === 'cli') {
339
            return true;
340
        }
341
342
        if (\array_key_exists('SHELL', $_ENV)) {
343
            return true;
344
        }
345
346
        if (empty($_SERVER[ 'REMOTE_ADDR' ]) && !isset($_SERVER[ 'HTTP_USER_AGENT' ]) && \count($_SERVER[ 'argv' ]) > 0) {
347
            return true;
348
        }
349
350
        if (!\array_key_exists('REQUEST_METHOD', $_SERVER)) {
351
            return true;
352
        }
353
354
        return false;
355
    }
356
}