Failed Conditions
Pull Request — master (#1)
by Yo
02:18
created

TestsStrategyListener::processEvent()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 31
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 31
ccs 21
cts 21
cp 1
rs 8.439
cc 6
eloc 19
nc 6
nop 2
crap 6
1
<?php
2
namespace Yoanm\PhpUnitExtended\Listener;
3
4
/**
5
 * @see https://github.com/yoanm/Readme/blob/master/TESTS_STRATEGY.md#rules-strict-mode-fails-if-risky-tests
6
 * Will convert a risky test regarding following option to failure
7
 *  =>phpunit process will return a failed result at end
8
 *
9
 * List of managed options :
10
 * - beStrictAboutOutputDuringTests="true" / --report-useless-tests
11
 * - checkForUnintentionallyCoveredCode="true" / --strict-coverage
12
 *      => in case forceCoversAnnotation is used, and the test execute code that are not listed by
13
 *          a @covers or @uses annotations
14
 * - beStrictAboutTestsThatDoNotTestAnything="true" / --disallow-test-output
15
 * - beStrictAboutChangesToGlobalState="true" / --strict-global-state
16
 *
17
 * @see https://github.com/yoanm/Readme/blob/master/strategy/tests/README.md#rules-real-coverage-risky-tests
18
 * Risky tests will be managed as not executed tests and so, code coverage generated by them will be removed
19
 *  => Allow failure based on coverage
20
 */
21
class TestsStrategyListener extends \PHPUnit_Framework_BaseTestListener
22
{
23
    /**
24
     * @param \PHPUnit_Framework_Test $test
25
     * @param \Exception              $e
26
     * @param float                   $time
27
     */
28 9
    public function addRiskyTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
29
    {
30
        /* Must be PHPUnit_Framework_TestCase instance to have access to "getTestResultObject" method */
31 9
        if ($test instanceof \PHPUnit_Framework_TestCase) {
32 9
            $reason = $this->processEvent($test, $e);
33 9
            if (null !== $reason) {
34 8
                $test->getTestResultObject()->addFailure(
35 8
                    $test,
36 8
                    new \PHPUnit_Framework_AssertionFailedError(
37 8
                        sprintf(
38 8
                            "Strict mode - %s :\n%s",
39 8
                            $reason,
40 8
                            $e->getMessage()
41 8
                        )
42 8
                    ),
43
                    $time
44 8
                );
45 8
            }
46 9
        }
47 9
    }
48
49
    /**
50
     * @param \PHPUnit_Framework_TestCase $test
51
     */
52 4
    protected function removeCoverageFor(\PHPUnit_Framework_TestCase $test)
53
    {
54 4
        $coverage = $test->getTestResultObject()->getCodeCoverage();
55 4
        if (null !== $coverage) {
56 3
            $id = sprintf('%s::%s', get_class($test), $test->getName());
57 3
            $data = $coverage->getData();
58 3
            foreach ($data as $fileName => $lineData) {
59 3
                foreach ($lineData as $lineNumber => $testIdList) {
60 3
                    if (is_array($testIdList)) {
61 3
                        foreach ($testIdList as $testIdKey => $testId) {
62 3
                            if ($id === $testId) {
63 3
                                unset($data[$fileName][$lineNumber][$testIdKey]);
64 3
                            }
65 3
                        }
66 3
                    }
67 3
                }
68 3
            }
69 3
            $coverage->setData($data);
70 3
        }
71 4
    }
72
73
    /**
74
     * @param \PHPUnit_Framework_TestCase $test
75
     * @param \Exception                  $e
76
     *
77
     * @return null|string
78
     */
79 9
    protected function processEvent(\PHPUnit_Framework_TestCase $test, \Exception $e)
80
    {
81 9
        $reason = null;
82 9
        switch (true) {
83
            /* beStrictAboutOutputDuringTests="true" */
84 9
            case $e instanceof \PHPUnit_Framework_OutputError:
85 4
                $reason = 'No output during test';
86
                /** Ack - remove coverage */
87 4
                $this->removeCoverageFor($test);
88
                /** END Ack */
89 4
                break;
90
            /* checkForUnintentionallyCoveredCode="true" */
91 5
            case $e instanceof \PHPUnit_Framework_UnintentionallyCoveredCodeError:
92 1
                $reason = 'Executed code must be defined with @covers and @uses annotations';
93 1
                break;
94 4
            default:
95 4
                if (preg_match('#\-\-\- Global variables before the test#', $e->getMessage())) {
96
                    /* beStrictAboutChangesToGlobalState="true" (no specific exception) for globals */
97 1
                    $reason = 'No global variable manipulation during test';
98 4
                } elseif (preg_match('#\-\-\- Static attributes before the test#', $e->getMessage())) {
99
                    /* beStrictAboutChangesToGlobalState="true" (no specific exception) for static var */
100
                    /* Only when beStrictAboutChangesToGlobalState="true" */
101 1
                    $reason = 'No static attribute manipulation during test';
102 3
                } elseif (preg_match('#This test did not perform any assertions#', $e->getMessage())) {
103
                    /* beStrictAboutTestsThatDoNotTestAnything="true" (no specific exception) */
104 1
                    $reason = 'No test that do not test anything';
105 1
                }
106 4
                break;
107 4
        }
108 9
        return $reason;
109
    }
110
}
111