Completed
Branch master (cb3538)
by Julian
02:11
created

ResultPrinter   C

Complexity

Total Complexity 58

Size/Duplication

Total Lines 525
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 78.74%

Importance

Changes 0
Metric Value
wmc 58
c 0
b 0
f 0
lcom 1
cbo 5
dl 0
loc 525
ccs 137
cts 174
cp 0.7874
rs 6.3005

28 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A addTest() 0 8 1
B start() 0 20 5
A println() 0 5 1
A flush() 0 5 1
A printResults() 0 8 1
A printFeedback() 0 18 2
A getHeader() 0 4 1
A addWarnings() 0 4 1
A getWarnings() 0 4 1
A isSuccessful() 0 4 2
A getFooter() 0 6 2
A getFailures() 0 6 1
A getErrors() 0 6 1
A getTotalCases() 0 4 1
A printTestWarnings() 0 10 3
A isSkippedIncompleTestCanBeTracked() 0 5 3
A processTestOverhead() 0 13 3
A printSkippedAndIncomplete() 0 9 3
A printFeedbackItem() 0 10 2
A getProgress() 0 9 2
A green() 0 9 2
A red() 0 9 2
A clearLogs() 0 6 2
A processReaderFeedback() 0 19 4
B getDefects() 0 20 5
A getFailedFooter() 0 14 1
B getSuccessFooter() 0 27 4

How to fix   Complexity   

Complex Class

Complex classes like ResultPrinter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ResultPrinter, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace ParaTest\Runners\PHPUnit;
3
4
use ParaTest\Logging\LogInterpreter;
5
use ParaTest\Logging\JUnit\Reader;
6
7
/**
8
 * Class ResultPrinter
9
 *
10
 * Used for outputing ParaTest results
11
 *
12
 * @package ParaTest\Runners\PHPUnit
13
 */
14
class ResultPrinter
15
{
16
    /**
17
     * A collection of ExecutableTest objects
18
     *
19
     * @var array
20
     */
21
    protected $suites = [];
22
23
    /**
24
     * @var \ParaTest\Logging\LogInterpreter
25
     */
26
    protected $results;
27
28
    /**
29
     * The number of tests results currently printed.
30
     * Used to determine when to tally current results
31
     * and start a new row
32
     *
33
     * @var int
34
     */
35
    protected $numTestsWidth;
36
37
    /**
38
     * Used for formatting results to a given width
39
     *
40
     * @var int
41
     */
42
    protected $maxColumn;
43
44
    /**
45
     * The total number of cases to be run
46
     *
47
     * @var int
48
     */
49
    protected $totalCases = 0;
50
51
    /**
52
     * The current column being printed to
53
     *
54
     * @var int
55
     */
56
    protected $column = 0;
57
58
    /**
59
     * @var \PHP_Timer
60
     */
61
    protected $timer;
62
63
    /**
64
     * The total number of cases printed so far
65
     *
66
     * @var int
67
     */
68
    protected $casesProcessed = 0;
69
70
    /**
71
     * Whether to display a red or green bar
72
     *
73
     * @var bool
74
     */
75
    protected $colors;
76
77
    /**
78
     * Warnings generated by the cases
79
     *
80
     * @var array
81
     */
82
    protected $warnings = [];
83
84
    /**
85
     * Number of columns
86
     *
87
     * @var integer
88
     */
89
    protected $numberOfColumns = 80;
90
91
    /**
92
     * Number of skipped or incomplete tests
93
     *
94
     * @var integer
95
     */
96
    protected $totalSkippedOrIncomplete = 0;
97
98
    /**
99
     * Do we need to try to process skipped/incompleted tests.
100
     *
101
     * @var boolean
102
     */
103
    protected $processSkipped = false;
104
105 27
    public function __construct(LogInterpreter $results)
106
    {
107 27
        $this->results = $results;
108 27
        $this->timer = new \PHP_Timer();
109 27
    }
110
111
    /**
112
     * Adds an ExecutableTest to the tracked results
113
     *
114
     * @param ExecutableTest $suite
115
     * @return $this
116
     */
117 16
    public function addTest(ExecutableTest $suite)
118
    {
119 16
        $this->suites[] = $suite;
120 16
        $increment = $suite->getTestCount();
121 16
        $this->totalCases = $this->totalCases + $increment;
122
123 16
        return $this;
124
    }
125
126
    /**
127
     * Initializes printing constraints, prints header
128
     * information and starts the test timer
129
     *
130
     * @param Options $options
131
     */
132 9
    public function start(Options $options)
133
    {
134 9
        $this->numTestsWidth = strlen((string) $this->totalCases);
135 9
        $this->maxColumn = $this->numberOfColumns
136 9
                         + (DIRECTORY_SEPARATOR == "\\" ? -1 : 0) // fix windows blank lines
137 9
                         - strlen($this->getProgress());
138 9
        printf(
139 9
            "\nRunning phpunit in %d process%s with %s%s\n\n",
140 9
            $options->processes,
0 ignored issues
show
Documentation introduced by
The property $processes is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
141 9
            $options->processes > 1 ? 'es' : '',
0 ignored issues
show
Documentation introduced by
The property $processes is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
142 9
            $options->phpunit,
0 ignored issues
show
Documentation introduced by
The property $phpunit is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
143 9
            $options->functional ? '. Functional mode is ON.' : ''
0 ignored issues
show
Documentation introduced by
The property $functional is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
144
        );
145 9
        if (isset($options->filtered['configuration'])) {
0 ignored issues
show
Documentation introduced by
The property $filtered is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
146 9
            printf("Configuration read from %s\n\n", $options->filtered['configuration']->getPath());
0 ignored issues
show
Documentation introduced by
The property $filtered is declared protected in ParaTest\Runners\PHPUnit\Options. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
147
        }
148 9
        $this->timer->start();
149 9
        $this->colors = $options->colors;
150 9
        $this->processSkipped = $this->isSkippedIncompleTestCanBeTracked($options);
151 9
    }
152
153
    /**
154
     * @param string $string
155
     */
156 2
    public function println($string = "")
157
    {
158 2
        $this->column = 0;
159 2
        print("$string\n");
160 2
    }
161
162
    /**
163
     * Prints all results and removes any log files
164
     * used for aggregating results
165
     */
166
    public function flush()
167
    {
168
        $this->printResults();
169
        $this->clearLogs();
170
    }
171
172
    /**
173
     * Print final results
174
     */
175 2
    public function printResults()
176
    {
177 2
        print $this->getHeader();
178 2
        print $this->getErrors();
179 2
        print $this->getFailures();
180 2
        print $this->getWarnings();
181 2
        print $this->getFooter();
182 2
    }
183
184
    /**
185
     * Prints the individual "quick" feedback for run
186
     * tests, that is the ".EF" items
187
     *
188
     * @param ExecutableTest $test
189
     */
190 11
    public function printFeedback(ExecutableTest $test)
191
    {
192
        try {
193 11
            $reader = new Reader($test->getTempFile());
194
        } catch (\InvalidArgumentException $e) {
195
            throw new \RuntimeException(sprintf(
196
                "%s\n" .
197
                "The process: %s\n" .
198
                "This means a PHPUnit process was unable to run \"%s\"\n" ,
199
                $e->getMessage(),
200
                $test->getLastCommand(),
201
                $test->getPath()
202
            ));
203
        }
204 11
        $this->results->addReader($reader);
205 11
        $this->processReaderFeedback($reader, $test->getTestCount());
206 11
        $this->printTestWarnings($test);
207 11
    }
208
209
    /**
210
     * Returns the header containing resource usage
211
     *
212
     * @return string
213
     */
214 3
    public function getHeader()
215
    {
216 3
        return "\n\n" . $this->timer->resourceUsage() . "\n\n";
217
    }
218
219
    /**
220
     * Add an array of warning strings. These cause the test run to be shown
221
     * as failed
222
     */
223
    public function addWarnings(array $warnings)
224
    {
225
        $this->warnings = array_merge($this->warnings, $warnings);
226
    }
227
228
    /**
229
     * Returns warning messages as a string
230
     */
231 2
    public function getWarnings()
232
    {
233 2
        return $this->getDefects($this->warnings, 'warning');
234
    }
235
236
    /**
237
     * Whether the test run is successful and has no warnings
238
     *
239
     * @return bool
240
     */
241 4
    public function isSuccessful()
242
    {
243 4
        return $this->results->isSuccessful() && count($this->warnings) == 0;
244
    }
245
246
    /**
247
     * Return the footer information reporting success
248
     * or failure
249
     *
250
     * @return string
251
     */
252 4
    public function getFooter()
253
    {
254 4
        return $this->isSuccessful()
255 1
                    ? $this->getSuccessFooter()
256 4
                    : $this->getFailedFooter();
257
    }
258
259
    /**
260
     * Returns the failure messages
261
     *
262
     * @return string
263
     */
264 3
    public function getFailures()
265
    {
266 3
        $failures = $this->results->getFailures();
0 ignored issues
show
Documentation Bug introduced by
The method getFailures does not exist on object<ParaTest\Logging\LogInterpreter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
267
268 3
        return $this->getDefects($failures, 'failure');
269
    }
270
271
    /**
272
     * Returns error messages
273
     *
274
     * @return string
275
     */
276 4
    public function getErrors()
277
    {
278 4
        $errors = $this->results->getErrors();
0 ignored issues
show
Documentation Bug introduced by
The method getErrors does not exist on object<ParaTest\Logging\LogInterpreter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
279
280 4
        return $this->getDefects($errors, 'error');
281
    }
282
283
    /**
284
     * Returns the total cases being printed
285
     *
286
     * @return int
287
     */
288 2
    public function getTotalCases()
289
    {
290 2
        return $this->totalCases;
291
    }
292
293
    /**
294
     * Process reader feedback and print it.
295
     *
296
     * @param  Reader $reader
297
     * @param  int    $expectedTestCount
298
     */
299 11
    protected function processReaderFeedback($reader, $expectedTestCount)
300
    {
301 11
        $feedbackItems = $reader->getFeedback();
302
303 11
        $actualTestCount = count($feedbackItems);
304
305 11
        $this->processTestOverhead($actualTestCount, $expectedTestCount);
306
307 11
        foreach ($feedbackItems as $item) {
308 11
            $this->printFeedbackItem($item);
309 11
            if ($item === 'S')  {
310
                $this->totalSkippedOrIncomplete++;
311
            }
312
        }
313
314 11
        if ($this->processSkipped) {
315 4
            $this->printSkippedAndIncomplete($actualTestCount, $expectedTestCount);
316
        }
317 11
    }
318
319
    /**
320
     * Prints test warnings.
321
     *
322
     * @param  ExecutableTest $test
323
     */
324 11
    protected function printTestWarnings($test)
325
    {
326 11
        $warnings = $test->getWarnings();
327 11
        if ($warnings) {
328
            $this->addWarnings($warnings);
329
            foreach ($warnings as $warning) {
330
                $this->printFeedbackItem('W');
331
            }
332
        }
333 11
    }
334
335
    /**
336
     * Is skipped/incomplete amount can be properly processed.
337
     *
338
     * @todo Skipped/Incomplete test tracking available only in functional mode for now
339
     *       or in regular mode but without group/exclude-group filters.
340
     *
341
     * @return boolean
342
     */
343 9
    protected function isSkippedIncompleTestCanBeTracked($options)
344
    {
345 9
        return $options->functional
346 9
            || (empty($options->groups) && empty($options->excludeGroups));
347
    }
348
349
    /**
350
     * Process test overhead.
351
     *
352
     * In some situations phpunit can return more tests then we expect and in that case
353
     * this method correct total amount of tests so paratest progress will be auto corrected.
354
     *
355
     * @todo May be we need to throw Exception here instead of silent correction.
356
     *
357
     * @param  int $actualTestCount
358
     * @param  int $expectedTestCount
359
     */
360 11
    protected function processTestOverhead($actualTestCount, $expectedTestCount)
361
    {
362 11
        $overhead = $actualTestCount - $expectedTestCount;
363 11
        if ($this->processSkipped) {
364 4
            if ($overhead > 0) {
365 1
                $this->totalCases += $overhead;
366
            } else {
367 3
                $this->totalSkippedOrIncomplete += -$overhead;
368
            }
369
        } else {
370 7
            $this->totalCases += $overhead;
371
        }
372 11
    }
373
374
    /**
375
     * Prints S for skipped and incomplete tests.
376
     *
377
     * If for some reason process return less tests than expected then we threat all remaining
378
     * as skipped or incomplete and print them as skipped (S letter)
379
     *
380
     * @param  int $actualTestCount
381
     * @param  int $expectedTestCount
382
     */
383 4
    protected function printSkippedAndIncomplete($actualTestCount, $expectedTestCount)
384
    {
385 4
        $overhead = $expectedTestCount - $actualTestCount;
386 4
        if ($overhead > 0) {
387
            for ($i = 0; $i < $overhead; $i++) {
388
                $this->printFeedbackItem("S");
389
            }
390
        }
391 4
    }
392
393
    /**
394
     * Prints a single "quick" feedback item and increments
395
     * the total number of processed cases and the column
396
     * position
397
     *
398
     * @param $item
399
     */
400 11
    protected function printFeedbackItem($item)
401
    {
402 11
        print $item;
403 11
        $this->column++;
404 11
        $this->casesProcessed++;
405 11
        if ($this->column == $this->maxColumn) {
406 2
            print $this->getProgress();
407 2
            $this->println();
408
        }
409 11
    }
410
411
    /**
412
     * Method that returns a formatted string
413
     * for a collection of errors or failures
414
     *
415
     * @param array $defects
416
     * @param $type
417
     * @return string
418
     */
419 5
    protected function getDefects(array $defects, $type)
420
    {
421 5
        $count = sizeof($defects);
422 5
        if ($count == 0) {
423 2
            return '';
424
        }
425 5
        $output = sprintf(
426 5
            "There %s %d %s%s:\n",
427 5
            ($count == 1) ? 'was' : 'were',
428
            $count,
429
            $type,
430 5
            ($count == 1) ? '' : 's'
431
        );
432
433 5
        for ($i = 1; $i <= sizeof($defects); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
434 5
            $output .= sprintf("\n%d) %s\n", $i, $defects[$i - 1]);
435
        }
436
437 5
        return $output;
438
    }
439
440
    /**
441
     * Prints progress for large test collections
442
     */
443 9
    protected function getProgress()
444
    {
445 9
        return sprintf(
446 9
            ' %' . $this->numTestsWidth . 'd / %' . $this->numTestsWidth . 'd (%3s%%)',
447 9
            $this->casesProcessed,
448 9
            $this->totalCases,
449 9
            floor(($this->totalCases ? $this->casesProcessed / $this->totalCases : 0) * 100)
450
        );
451
    }
452
453
    /**
454
     * Get the footer for a test collection that had tests with
455
     * failures or errors
456
     *
457
     * @return string
458
     */
459 3
    private function getFailedFooter()
460
    {
461 3
        $formatString = "FAILURES!\nTests: %d, Assertions: %d, Failures: %d, Errors: %d.\n";
462
463 3
        return "\n" . $this->red(
464 3
            sprintf(
465
                $formatString,
466 3
                $this->results->getTotalTests(),
0 ignored issues
show
Documentation Bug introduced by
The method getTotalTests does not exist on object<ParaTest\Logging\LogInterpreter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
467 3
                $this->results->getTotalAssertions(),
0 ignored issues
show
Documentation Bug introduced by
The method getTotalAssertions does not exist on object<ParaTest\Logging\LogInterpreter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
468 3
                $this->results->getTotalFailures(),
0 ignored issues
show
Documentation Bug introduced by
The method getTotalFailures does not exist on object<ParaTest\Logging\LogInterpreter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
469 3
                $this->results->getTotalErrors()
0 ignored issues
show
Documentation Bug introduced by
The method getTotalErrors does not exist on object<ParaTest\Logging\LogInterpreter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
470
            )
471
        );
472
    }
473
474
    /**
475
     * Get the footer for a test collection containing all successful
476
     * tests
477
     *
478
     * @return string
479
     */
480 1
    private function getSuccessFooter()
481
    {
482 1
        $tests = $this->totalCases;
483 1
        $asserts = $this->results->getTotalAssertions();
0 ignored issues
show
Documentation Bug introduced by
The method getTotalAssertions does not exist on object<ParaTest\Logging\LogInterpreter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
484
485 1
        if ($this->totalSkippedOrIncomplete > 0) {
486
            // phpunit 4.5 produce NOT plural version for test(s) and assertion(s) in that case
487
            // also it shows result in standard color scheme
488
            return sprintf(
489
                "OK, but incomplete, skipped, or risky tests!\n"
490
                . "Tests: %d, Assertions: %d, Incomplete: %d.\n",
491
                $tests,
492
                $asserts,
493
                $this->totalSkippedOrIncomplete
494
            );
495
        } else {
496
            // phpunit 4.5 produce plural version for test(s) and assertion(s) in that case
497
            // also it shows result as black text on green background
498 1
            return $this->green(sprintf(
499 1
                "OK (%d test%s, %d assertion%s)\n",
500
                $tests,
501 1
                ($tests == 1) ? '' : 's',
502
                $asserts,
503 1
                ($asserts == 1) ? '' : 's'
504
            ));
505
        }
506
    }
507
508 1
    private function green($text)
509
    {
510 1
        if ($this->colors) {
511
            return "\x1b[30;42m\x1b[2K"
512
                . $text
513
                . "\x1b[0m\x1b[2K";
514
        }
515 1
        return $text;
516
    }
517
518 3
    private function red($text)
519
    {
520 3
        if ($this->colors) {
521
            return "\x1b[37;41m\x1b[2K"
522
                . $text
523
                . "\x1b[0m\x1b[2K";
524
        }
525 3
        return $text;
526
    }
527
528
    /**
529
     * Deletes all the temporary log files for ExecutableTest objects
530
     * being printed
531
     */
532
    private function clearLogs()
533
    {
534
        foreach ($this->suites as $suite) {
535
            $suite->deleteFile();
536
        }
537
    }
538
}
539