Completed
Pull Request — master (#86)
by Alessandro
04:41
created

LogPrinter::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Paraunit\Parser\JSON;
4
5
/**
6
 * This class comes from \PHPUnit_Util_Log_JSON.
7
 * It's copied and refactored here because it's deprecated in PHPUnit 5.7 and it will be dropped in PHPUnit 6
8
 *
9
 * Class LogPrinter
10
 * @package Paraunit\Parser\JSON
11
 */
12
class LogPrinter extends \PHPUnit_Util_Printer implements \PHPUnit_Framework_TestListener
13
{
14
    /** @var string */
15
    private $logDirectory;
16
17
    /** @var int */
18
    private $testSuiteLevel;
19
20
    /**
21
     * LogPrinter constructor.
22
     * @param mixed $out
23
     */
24 2
    public function __construct($out = null)
25
    {
26 2
        if (substr($out, -1) !== DIRECTORY_SEPARATOR) {
27 2
            $out .= DIRECTORY_SEPARATOR;
28
        }
29
30 2
        $this->logDirectory = $out;
31 2
        $this->testSuiteLevel = 0;
32 2
    }
33
34
    /**
35
     * An error occurred.
36
     *
37
     * @param \PHPUnit_Framework_Test $test
38
     * @param \Exception              $e
39
     * @param float                   $time
40
     */
41 View Code Duplication
    public function addError(\PHPUnit_Framework_Test $test, \Exception $e, $time)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
42
    {
43
        $this->writeCase(
44
            'error',
45
            $time,
46
            \PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
0 ignored issues
show
Bug introduced by
It seems like \PHPUnit_Util_Filter::ge...edStacktrace($e, false) targeting PHPUnit_Util_Filter::getFilteredStacktrace() can also be of type string; however, Paraunit\Parser\JSON\LogPrinter::writeCase() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
47
            \PHPUnit_Framework_TestFailure::exceptionToString($e),
48
            $test
0 ignored issues
show
Documentation introduced by
$test is of type object<PHPUnit_Framework_Test>, but the function expects a object<PHPUnit_Framework_TestCase>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
49
        );
50
51
        $this->currentTestPass = false;
0 ignored issues
show
Bug introduced by
The property currentTestPass does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
52
    }
53
54
    /**
55
     * A warning occurred.
56
     *
57
     * @param \PHPUnit_Framework_Test    $test
58
     * @param \PHPUnit_Framework_Warning $e
59
     * @param float                      $time
60
     */
61 View Code Duplication
    public function addWarning(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_Warning $e, $time)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
62
    {
63
        $this->writeCase(
64
            'warning',
65
            $time,
66
            \PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
0 ignored issues
show
Bug introduced by
It seems like \PHPUnit_Util_Filter::ge...edStacktrace($e, false) targeting PHPUnit_Util_Filter::getFilteredStacktrace() can also be of type string; however, Paraunit\Parser\JSON\LogPrinter::writeCase() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
67
            \PHPUnit_Framework_TestFailure::exceptionToString($e),
68
            $test
0 ignored issues
show
Documentation introduced by
$test is of type object<PHPUnit_Framework_Test>, but the function expects a object<PHPUnit_Framework_TestCase>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
69
        );
70
71
        $this->currentTestPass = false;
72
    }
73
74
    /**
75
     * A failure occurred.
76
     *
77
     * @param \PHPUnit_Framework_Test                 $test
78
     * @param \PHPUnit_Framework_AssertionFailedError $e
79
     * @param float                                   $time
80
     */
81 View Code Duplication
    public function addFailure(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_AssertionFailedError $e, $time)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
82
    {
83
        $this->writeCase(
84
            'fail',
85
            $time,
86
            \PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
0 ignored issues
show
Bug introduced by
It seems like \PHPUnit_Util_Filter::ge...edStacktrace($e, false) targeting PHPUnit_Util_Filter::getFilteredStacktrace() can also be of type string; however, Paraunit\Parser\JSON\LogPrinter::writeCase() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
87
            \PHPUnit_Framework_TestFailure::exceptionToString($e),
88
            $test
0 ignored issues
show
Documentation introduced by
$test is of type object<PHPUnit_Framework_Test>, but the function expects a object<PHPUnit_Framework_TestCase>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
89
        );
90
91
        $this->currentTestPass = false;
92
    }
93
94
    /**
95
     * Incomplete test.
96
     *
97
     * @param \PHPUnit_Framework_Test $test
98
     * @param \Exception              $e
99
     * @param float                   $time
100
     */
101 View Code Duplication
    public function addIncompleteTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
102
    {
103
        $this->writeCase(
104
            'error',
105
            $time,
106
            \PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
0 ignored issues
show
Bug introduced by
It seems like \PHPUnit_Util_Filter::ge...edStacktrace($e, false) targeting PHPUnit_Util_Filter::getFilteredStacktrace() can also be of type string; however, Paraunit\Parser\JSON\LogPrinter::writeCase() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
107
            'Incomplete Test: ' . $e->getMessage(),
108
            $test
0 ignored issues
show
Documentation introduced by
$test is of type object<PHPUnit_Framework_Test>, but the function expects a object<PHPUnit_Framework_TestCase>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
109
        );
110
111
        $this->currentTestPass = false;
112
    }
113
114
    /**
115
     * Risky test.
116
     *
117
     * @param \PHPUnit_Framework_Test $test
118
     * @param \Exception              $e
119
     * @param float                   $time
120
     */
121 View Code Duplication
    public function addRiskyTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
122
    {
123
        $this->writeCase(
124
            'error',
125
            $time,
126
            \PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
0 ignored issues
show
Bug introduced by
It seems like \PHPUnit_Util_Filter::ge...edStacktrace($e, false) targeting PHPUnit_Util_Filter::getFilteredStacktrace() can also be of type string; however, Paraunit\Parser\JSON\LogPrinter::writeCase() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
127
            'Risky Test: ' . $e->getMessage(),
128
            $test
0 ignored issues
show
Documentation introduced by
$test is of type object<PHPUnit_Framework_Test>, but the function expects a object<PHPUnit_Framework_TestCase>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
129
        );
130
131
        $this->currentTestPass = false;
132
    }
133
134
    /**
135
     * Skipped test.
136
     *
137
     * @param \PHPUnit_Framework_Test $test
138
     * @param \Exception              $e
139
     * @param float                   $time
140
     */
141 View Code Duplication
    public function addSkippedTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
142
    {
143
        $this->writeCase(
144
            'error',
145
            $time,
146
            \PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
0 ignored issues
show
Bug introduced by
It seems like \PHPUnit_Util_Filter::ge...edStacktrace($e, false) targeting PHPUnit_Util_Filter::getFilteredStacktrace() can also be of type string; however, Paraunit\Parser\JSON\LogPrinter::writeCase() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
147
            'Skipped Test: ' . $e->getMessage(),
148
            $test
0 ignored issues
show
Documentation introduced by
$test is of type object<PHPUnit_Framework_Test>, but the function expects a object<PHPUnit_Framework_TestCase>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
149
        );
150
151
        $this->currentTestPass = false;
152
    }
153
154
    /**
155
     * A testsuite started.
156
     *
157
     * @param \PHPUnit_Framework_TestSuite $suite
158
     */
159 1
    public function startTestSuite(\PHPUnit_Framework_TestSuite $suite)
160
    {
161 1
        if ($this->testSuiteLevel === 0) {
162 1
            $logFilename = $this->getLogFilename($suite);
163
164 1
            $logDir = dirname($logFilename);
165 1 View Code Duplication
            if (! @mkdir($logDir, 0777, true) && !is_dir($logDir)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
166
                throw new \RuntimeException('Cannot create folder for JSON logs');
167
            }
168
169 1
            $this->out = fopen($logFilename, 'wt');
170
        }
171
172 1
        $this->testSuiteLevel++;
173 1
        $this->currentTestSuiteName = $suite->getName();
0 ignored issues
show
Bug introduced by
The property currentTestSuiteName does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
174 1
        $this->currentTestName      = '';
0 ignored issues
show
Bug introduced by
The property currentTestName does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
175
176 1
        $this->write(
177
            array(
0 ignored issues
show
Documentation introduced by
array('event' => 'suiteS...ests' => count($suite)) is of type array<string,string|inte...ng","tests":"integer"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
178 1
                'event' => 'suiteStart',
179 1
                'suite' => $this->currentTestSuiteName,
180 1
                'tests' => count($suite)
181
            )
182
        );
183 1
    }
184
185
    /**
186
     * A testsuite ended.
187
     *
188
     * @param \PHPUnit_Framework_TestSuite $suite
189
     */
190
    public function endTestSuite(\PHPUnit_Framework_TestSuite $suite)
191
    {
192
        $this->testSuiteLevel--;
193
        $this->currentTestSuiteName = '';
194
        $this->currentTestName      = '';
195
    }
196
197
    /**
198
     * A test started.
199
     *
200
     * @param \PHPUnit_Framework_Test $test
201
     */
202
    public function startTest(\PHPUnit_Framework_Test $test)
203
    {
204
        $this->currentTestName = \PHPUnit_Util_Test::describe($test);
205
        $this->currentTestPass = true;
206
207
        $this->write(
208
            array(
0 ignored issues
show
Documentation introduced by
array('event' => 'testSt...$this->currentTestName) is of type array<string,*,{"event":...suite":"?","test":"*"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
209
                'event' => 'testStart',
210
                'suite' => $this->currentTestSuiteName,
211
                'test'  => $this->currentTestName
212
            )
213
        );
214
    }
215
216
    /**
217
     * A test ended.
218
     *
219
     * @param \PHPUnit_Framework_Test $test
220
     * @param float                  $time
221
     */
222
    public function endTest(\PHPUnit_Framework_Test $test, $time)
223
    {
224
        if ($this->currentTestPass) {
225
            $this->writeCase('pass', $time, array(), '', $test);
0 ignored issues
show
Documentation introduced by
$test is of type object<PHPUnit_Framework_Test>, but the function expects a object<PHPUnit_Framework_TestCase>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
226
        }
227
    }
228
229
    /**
230
     * @param string                           $status
231
     * @param float                            $time
232
     * @param array                            $trace
233
     * @param string                           $message
234
     * @param \PHPUnit_Framework_TestCase|null $test
235
     */
236
    protected function writeCase($status, $time, array $trace = array(), $message = '', $test = null)
237
    {
238
        $output = '';
239
        // take care of TestSuite producing error (e.g. by running into exception) as TestSuite doesn't have hasOutput
240
        if ($test !== null && method_exists($test, 'hasOutput') && $test->hasOutput()) {
241
            $output = $test->getActualOutput();
242
        }
243
        $this->write(
244
            array(
0 ignored issues
show
Documentation introduced by
array('event' => 'test',...), 'output' => $output) is of type array<string,?,{"event":...ng","output":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
245
                'event'   => 'test',
246
                'suite'   => $this->currentTestSuiteName,
247
                'test'    => $this->currentTestName,
248
                'status'  => $status,
249
                'time'    => $time,
250
                'trace'   => $trace,
251
                'message' => \PHPUnit_Util_String::convertToUtf8($message),
252
                'output'  => $output,
253
            )
254
        );
255
    }
256
257
    /**
258
     * @param string $buffer
259
     */
260
    public function write($buffer)
261
    {
262 1
        array_walk_recursive($buffer, function (&$input) {
263 1
            if (is_string($input)) {
264 1
                $input = \PHPUnit_Util_String::convertToUtf8($input);
265
            }
266 1
        });
267
268 1
        $flags = 0;
269
270 1
        if (defined('JSON_PRETTY_PRINT')) {
271 1
            $flags |= JSON_PRETTY_PRINT;
272
        }
273
274 1
        parent::write(json_encode($buffer, $flags));
275 1
    }
276
277
    /**
278
     * @param \PHPUnit_Framework_TestSuite $suite
279
     * @return string
280
     */
281 2
    private function getLogFilename(\PHPUnit_Framework_TestSuite $suite)
282
    {
283 2
        $testFilename = $this->getTestFilename($suite);
284
        
285 2
        return $this->logDirectory . md5($testFilename) . '.json.log';
286
    }
287
288
    /**
289
     * @param \PHPUnit_Framework_TestSuite $suite
290
     * @return string
291
     */
292 2
    private function getTestFilename(\PHPUnit_Framework_TestSuite $suite)
293
    {
294 2
        $reflection = new \ReflectionClass($suite->getName());
295
        
296 2
        return $reflection->getFileName();
297
    }
298
}
299