Passed
Push — master ( 92d243...5a69a1 )
by Eric
12:07
created

Utils::isPossiblyClover()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 10
nc 3
nop 1
dl 0
loc 19
rs 9.6111
c 1
b 0
f 0
ccs 10
cts 10
cp 1
crap 5
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of PHPUnit Coverage Check.
7
 *
8
 * (c) Eric Sizemore <[email protected]>
9
 * (c) Richard Regeer <[email protected]>
10
 *
11
 * This source file is subject to the MIT license. For the full copyright,
12
 * license information, and credits/acknowledgements, please view the LICENSE
13
 * and README files that were distributed with this source code.
14
 */
15
16
namespace Esi\CoverageCheck;
17
18
use Exception;
19
use RuntimeException;
20
use SimpleXMLElement;
21
22
use function file_exists;
23
use function libxml_clear_errors;
24
use function libxml_get_errors;
25
use function libxml_use_internal_errors;
26
use function property_exists;
27
use function sprintf;
28
use function trim;
29
30
use const LIBXML_ERR_ERROR;
31
use const LIBXML_ERR_FATAL;
32
use const LIBXML_ERR_WARNING;
33
use const PHP_EOL;
34
35
final class Utils
36
{
37
    /**
38
     * Returns the given number formatted and rounded for percentage.
39
     */
40 10
    public static function formatCoverage(float $number): string
41
    {
42 10
        return sprintf('%0.2F%%', $number);
43
    }
44
45
    /**
46
     * Attempts to determine if we are actually using a PHPUnit generated clover file.
47
     *
48
     * As of 2024/03/28, the Clover XML report generated by PHPUnit (using phpunit-code-coverage) does
49
     * not validate against the official Atlassian/OpenClover clover XSD.
50
     *
51
     * @see https://bitbucket.org/atlassian/clover/raw/master/etc/schema/clover.xsd
52
     * @see https://github.com/sebastianbergmann/php-code-coverage/issues/578
53
     *
54
     * So this is a workaround of sorts.
55
     */
56 20
    public static function isPossiblyClover(SimpleXMLElement $xml): bool
57
    {
58 20
        if ($xml->getName() !== 'coverage') {
59 2
            return false;
60
        }
61
62 18
        $hasChildren = $xml->children();
63
64
        if (
65 18
            !property_exists($hasChildren, 'project')
66 16
            || !property_exists($hasChildren->project, 'metrics')
67 18
            || (array) $hasChildren->project->metrics === []
68
        ) {
69 4
            return false;
70
        }
71
72 14
        unset($hasChildren);
73
74 14
        return true;
75
    }
76
77
    /**
78
     * Handles parsing the XML data returned by CoverageCheck::loadMetrics().
79
     *
80
     * Attempts to gather any potential errors returned by SimpleXml/LibXml and wrap them
81
     * in a RuntimeException.
82
     *
83
     * @see https://www.php.net/SimpleXMLElement
84
     * @see https://www.php.net/libxml_use_internal_errors
85
     * @see https://www.php.net/libxml_get_errors
86
     *
87
     * @throws RuntimeException For any xml parser related errors.
88
     */
89 21
    public static function parseXml(string $xmlData): SimpleXMLElement
90
    {
91 21
        static $errorLevels = [
92 21
            LIBXML_ERR_WARNING => 'Warning',
93 21
            LIBXML_ERR_ERROR   => 'Error',
94 21
            LIBXML_ERR_FATAL   => 'Fatal Error',
95 21
        ];
96
97 21
        libxml_use_internal_errors(true);
98
99
        try {
100 21
            $xml = new SimpleXMLElement($xmlData);
101 1
        } catch (Exception) {
102 1
            $errorMessage = PHP_EOL;
103
104 1
            foreach (libxml_get_errors() as $error) {
105 1
                $errorMessage .= sprintf(
106 1
                    '%s %d: %s. Line %d Column %d',
107 1
                    $errorLevels[$error->level],
108 1
                    $error->code,
109 1
                    trim($error->message),
110 1
                    $error->line,
111 1
                    $error->column
112 1
                ) . PHP_EOL;
113
            }
114
115 1
            throw new RuntimeException(sprintf('Unable to load Clover XML data. LibXml returned: %s', $errorMessage));
116
        } finally {
117 21
            libxml_clear_errors();
118 21
            libxml_use_internal_errors(false);
119
        }
120
121 20
        return $xml;
122
    }
123
124
    /**
125
     * A simple file_exists check on the Clover file.
126
     */
127 25
    public static function validateCloverFile(string $cloverFile): bool
128
    {
129 25
        return ($cloverFile !== '' && file_exists($cloverFile));
130
    }
131
132
    /**
133
     * A simple check to determine if threshold is within accepted range (Min. 1, Max. 100).
134
     */
135 24
    public static function validateThreshold(int $threshold): bool
136
    {
137 24
        return ($threshold > 0 && $threshold <= 100);
138
    }
139
}
140