Configuration::getSuites()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 0
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ParaTest\Runners\PHPUnit;
6
7
/**
8
 * Class Configuration.
9
 *
10
 * Stores information about the phpunit xml
11
 * configuration being used to run tests
12
 */
13
class Configuration
14
{
15
    /**
16
     * Path to the configuration file.
17
     *
18
     * @var string
19
     */
20
    protected $path;
21
22
    /**
23
     * @var \SimpleXMLElement
24
     */
25
    protected $xml;
26
27
    protected $availableNodes = ['exclude', 'file', 'directory', 'testsuite'];
28
29
    /**
30
     * A collection of datastructures
31
     * build from the <testsuite> nodes inside of a
32
     * PHPUnit configuration.
33
     *
34
     * @var array
35
     */
36
    protected $suites = [];
37
38 59
    public function __construct(string $path)
39
    {
40 59
        $this->path = $path;
41 59
        if (file_exists($path)) {
42 52
            $this->xml = simplexml_load_string(file_get_contents($path));
43
        }
44 59
    }
45
46
    /**
47
     * Converting the configuration to a string
48
     * returns the configuration path.
49
     *
50
     * @return string
51
     */
52 3
    public function __toString(): string
53
    {
54 3
        return $this->path;
55
    }
56
57
    /**
58
     * Get the bootstrap PHPUnit configuration attribute.
59
     *
60
     * @return string The bootstrap attribute or empty string if not set
61
     */
62 4
    public function getBootstrap(): string
63
    {
64 4
        if ($this->xml) {
65 4
            return (string) $this->xml->attributes()->bootstrap;
66
        }
67
68
        return '';
69
    }
70
71
    /**
72
     * Returns the path to the phpunit configuration
73
     * file.
74
     *
75
     * @return string
76
     */
77 15
    public function getPath(): string
78
    {
79 15
        return $this->path;
80
    }
81
82
    /**
83
     * Return the contents of the <testsuite> nodes
84
     * contained in a PHPUnit configuration.
85
     *
86
     * @return SuitePath[][]|null
87
     */
88 6
    public function getSuites()
89
    {
90 6
        if (!$this->xml) {
91 1
            return;
92
        }
93 5
        $suites = [];
94 5
        $nodes = $this->xml->xpath('//testsuites/testsuite');
95
96 5
        foreach ($nodes as $node) {
97 5
            $suites = array_merge_recursive($suites, $this->getSuiteByName((string) $node['name']));
98
        }
99
100 4
        return $suites;
101
    }
102
103
    /**
104
     * Return the contents of the <testsuite> nodes
105
     * contained in a PHPUnit configuration.
106
     *
107
     * @param string $suiteName
108
     *
109
     * @return SuitePath[]|null
110
     */
111 15
    public function getSuiteByName(string $suiteName)
112
    {
113 15
        $nodes = $this->xml->xpath(sprintf('//testsuite[@name="%s"]', $suiteName));
114
115 15
        $suites = [];
116 15
        $excludedPaths = [];
117 15
        foreach ($nodes as $node) {
118 15
            foreach ($this->availableNodes as $nodeName) {
119 15
                foreach ($node->{$nodeName} as $nodeContent) {
120
                    switch ($nodeName) {
121 15
                        case 'exclude':
122 3
                            foreach ($this->getSuitePaths((string) $nodeContent) as $excludedPath) {
123 3
                                $excludedPaths[$excludedPath] = $excludedPath;
124
                            }
125 3
                            break;
126 15
                        case 'testsuite':
127 1
                            $suites = array_merge_recursive($suites, $this->getSuiteByName((string) $nodeContent));
128 1
                            break;
129 15
                        case 'directory':
130
                            // Replicate behaviour of PHPUnit
131
                            // if a directory is included and excluded at the same time, then it is considered included
132 12
                            foreach ($this->getSuitePaths((string) $nodeContent) as $dir) {
133 11
                                if (array_key_exists($dir, $excludedPaths)) {
134 11
                                    unset($excludedPaths[$dir]);
135
                                }
136
                            }
137
                            // no break on purpose
138
                        default:
139 14
                            foreach ($this->getSuitePaths((string) $nodeContent) as $path) {
140 14
                                $suites[(string) $node['name']][] = new SuitePath(
141 14
                                    $path,
142 14
                                    $excludedPaths,
143 14
                                    (string) $nodeContent->attributes()->suffix
144
                                );
145
                            }
146 15
                            break;
147
                    }
148
                }
149
            }
150
        }
151
152 14
        return $suites;
153
    }
154
155
    /**
156
     * Return the path of the directory
157
     * that contains the phpunit configuration.
158
     *
159
     * @return string
160
     */
161 19
    public function getConfigDir(): string
162
    {
163 19
        return dirname($this->path) . DIRECTORY_SEPARATOR;
164
    }
165
166
    /**
167
     * Returns a suite paths relative to the config file.
168
     *
169
     * @param $path
170
     *
171
     * @return array|string[]
172
     */
173 15
    public function getSuitePaths(string $path)
174
    {
175 15
        $real = realpath($this->getConfigDir() . $path);
176
177 15
        if ($real !== false) {
178 13
            return [$real];
179
        }
180
181 2
        if ($this->isGlobRequired($path)) {
182 1
            $paths = [];
183 1
            foreach (glob($this->getConfigDir() . $path, GLOB_ONLYDIR) as $path) {
184 1
                if (($path = realpath($path)) !== false) {
185 1
                    $paths[] = $path;
186
                }
187
            }
188
189 1
            return $paths;
190
        }
191
192 1
        throw new \RuntimeException("Suite path $path could not be found");
193
    }
194
195
    /**
196
     * Returns true if path needs globbing (like a /path/*-to/string).
197
     *
198
     * @param string $path
199
     *
200
     * @return bool
201
     */
202 2
    public function isGlobRequired(string $path): bool
203
    {
204 2
        return strpos($path, '*') !== false;
205
    }
206
}
207